diff --git a/crates/activity_indicator/src/activity_indicator.rs b/crates/activity_indicator/src/activity_indicator.rs index 973f845c17..8c6f5aa176 100644 --- a/crates/activity_indicator/src/activity_indicator.rs +++ b/crates/activity_indicator/src/activity_indicator.rs @@ -3,9 +3,9 @@ use editor::Editor; use extension_host::ExtensionStore; use futures::StreamExt; use gpui::{ - actions, percentage, Animation, AnimationExt as _, AppContext, CursorStyle, EventEmitter, - InteractiveElement as _, Model, ParentElement as _, Render, SharedString, - StatefulInteractiveElement, Styled, Transformation, View, ViewContext, VisualContext as _, + actions, percentage, Animation, AnimationExt as _, App, Context, CursorStyle, Entity, + EventEmitter, InteractiveElement as _, ParentElement as _, Render, SharedString, + StatefulInteractiveElement, Styled, Transformation, Window, }; use language::{LanguageRegistry, LanguageServerBinaryStatus, LanguageServerId}; use lsp::LanguageServerName; @@ -27,8 +27,8 @@ pub enum Event { pub struct ActivityIndicator { statuses: Vec, - project: Model, - auto_updater: Option>, + project: Entity, + auto_updater: Option>, context_menu_handle: PopoverMenuHandle, } @@ -46,22 +46,24 @@ struct PendingWork<'a> { struct Content { icon: Option, message: String, - on_click: Option)>>, + on_click: + Option)>>, } impl ActivityIndicator { pub fn new( workspace: &mut Workspace, languages: Arc, - cx: &mut ViewContext, - ) -> View { + window: &mut Window, + cx: &mut Context, + ) -> Entity { let project = workspace.project().clone(); let auto_updater = AutoUpdater::get(cx); - let this = cx.new_view(|cx: &mut ViewContext| { + let this = cx.new(|cx| { let mut status_events = languages.language_server_binary_statuses(); cx.spawn(|this, mut cx| async move { while let Some((name, status)) = status_events.next().await { - this.update(&mut cx, |this, cx| { + this.update(&mut cx, |this: &mut ActivityIndicator, cx| { this.statuses.retain(|s| s.name != name); this.statuses.push(LspStatus { name, status }); cx.notify(); @@ -70,6 +72,7 @@ impl ActivityIndicator { anyhow::Ok(()) }) .detach(); + cx.observe(&project, |_, _, cx| cx.notify()).detach(); if let Some(auto_updater) = auto_updater.as_ref() { @@ -84,13 +87,13 @@ impl ActivityIndicator { } }); - cx.subscribe(&this, move |_, _, event, cx| match event { + cx.subscribe_in(&this, window, move |_, _, event, window, cx| match event { Event::ShowError { lsp_name, error } => { let create_buffer = project.update(cx, |project, cx| project.create_buffer(cx)); let project = project.clone(); let error = error.clone(); let lsp_name = lsp_name.clone(); - cx.spawn(|workspace, mut cx| async move { + cx.spawn_in(window, |workspace, mut cx| async move { let buffer = create_buffer.await?; buffer.update(&mut cx, |buffer, cx| { buffer.edit( @@ -103,13 +106,14 @@ impl ActivityIndicator { ); buffer.set_capability(language::Capability::ReadOnly, cx); })?; - workspace.update(&mut cx, |workspace, cx| { + workspace.update_in(&mut cx, |workspace, window, cx| { workspace.add_item_to_active_pane( - Box::new(cx.new_view(|cx| { - Editor::for_buffer(buffer, Some(project.clone()), cx) + Box::new(cx.new(|cx| { + Editor::for_buffer(buffer, Some(project.clone()), window, cx) })), None, true, + window, cx, ); })?; @@ -123,7 +127,7 @@ impl ActivityIndicator { this } - fn show_error_message(&mut self, _: &ShowErrorMessage, cx: &mut ViewContext) { + fn show_error_message(&mut self, _: &ShowErrorMessage, _: &mut Window, cx: &mut Context) { self.statuses.retain(|status| { if let LanguageServerBinaryStatus::Failed { error } = &status.status { cx.emit(Event::ShowError { @@ -139,7 +143,12 @@ impl ActivityIndicator { cx.notify(); } - fn dismiss_error_message(&mut self, _: &DismissErrorMessage, cx: &mut ViewContext) { + fn dismiss_error_message( + &mut self, + _: &DismissErrorMessage, + _: &mut Window, + cx: &mut Context, + ) { if let Some(updater) = &self.auto_updater { updater.update(cx, |updater, cx| { updater.dismiss_error(cx); @@ -150,7 +159,7 @@ impl ActivityIndicator { fn pending_language_server_work<'a>( &self, - cx: &'a AppContext, + cx: &'a App, ) -> impl Iterator> { self.project .read(cx) @@ -178,12 +187,12 @@ impl ActivityIndicator { fn pending_environment_errors<'a>( &'a self, - cx: &'a AppContext, + cx: &'a App, ) -> impl Iterator { self.project.read(cx).shell_environment_errors(cx) } - fn content_to_render(&mut self, cx: &mut ViewContext) -> Option { + fn content_to_render(&mut self, cx: &mut Context) -> Option { // Show if any direnv calls failed if let Some((&worktree_id, error)) = self.pending_environment_errors(cx).next() { return Some(Content { @@ -193,11 +202,11 @@ impl ActivityIndicator { .into_any_element(), ), message: error.0.clone(), - on_click: Some(Arc::new(move |this, cx| { + on_click: Some(Arc::new(move |this, window, cx| { this.project.update(cx, |project, cx| { project.remove_environment_error(cx, worktree_id); }); - cx.dispatch_action(Box::new(workspace::OpenLog)); + window.dispatch_action(Box::new(workspace::OpenLog), cx); })), }); } @@ -280,10 +289,10 @@ impl ActivityIndicator { } ) ), - on_click: Some(Arc::new(move |this, cx| { + on_click: Some(Arc::new(move |this, window, cx| { this.statuses .retain(|status| !downloading.contains(&status.name)); - this.dismiss_error_message(&DismissErrorMessage, cx) + this.dismiss_error_message(&DismissErrorMessage, window, cx) })), }); } @@ -308,10 +317,10 @@ impl ActivityIndicator { } ), ), - on_click: Some(Arc::new(move |this, cx| { + on_click: Some(Arc::new(move |this, window, cx| { this.statuses .retain(|status| !checking_for_update.contains(&status.name)); - this.dismiss_error_message(&DismissErrorMessage, cx) + this.dismiss_error_message(&DismissErrorMessage, window, cx) })), }); } @@ -336,8 +345,8 @@ impl ActivityIndicator { acc }), ), - on_click: Some(Arc::new(|this, cx| { - this.show_error_message(&Default::default(), cx) + on_click: Some(Arc::new(|this, window, cx| { + this.show_error_message(&Default::default(), window, cx) })), }); } @@ -351,11 +360,11 @@ impl ActivityIndicator { .into_any_element(), ), message: format!("Formatting failed: {}. Click to see logs.", failure), - on_click: Some(Arc::new(|indicator, cx| { + on_click: Some(Arc::new(|indicator, window, cx| { indicator.project.update(cx, |project, cx| { project.reset_last_formatting_failure(cx); }); - cx.dispatch_action(Box::new(workspace::OpenLog)); + window.dispatch_action(Box::new(workspace::OpenLog), cx); })), }); } @@ -370,8 +379,8 @@ impl ActivityIndicator { .into_any_element(), ), message: "Checking for Zed updates…".to_string(), - on_click: Some(Arc::new(|this, cx| { - this.dismiss_error_message(&DismissErrorMessage, cx) + on_click: Some(Arc::new(|this, window, cx| { + this.dismiss_error_message(&DismissErrorMessage, window, cx) })), }), AutoUpdateStatus::Downloading => Some(Content { @@ -381,8 +390,8 @@ impl ActivityIndicator { .into_any_element(), ), message: "Downloading Zed update…".to_string(), - on_click: Some(Arc::new(|this, cx| { - this.dismiss_error_message(&DismissErrorMessage, cx) + on_click: Some(Arc::new(|this, window, cx| { + this.dismiss_error_message(&DismissErrorMessage, window, cx) })), }), AutoUpdateStatus::Installing => Some(Content { @@ -392,8 +401,8 @@ impl ActivityIndicator { .into_any_element(), ), message: "Installing Zed update…".to_string(), - on_click: Some(Arc::new(|this, cx| { - this.dismiss_error_message(&DismissErrorMessage, cx) + on_click: Some(Arc::new(|this, window, cx| { + this.dismiss_error_message(&DismissErrorMessage, window, cx) })), }), AutoUpdateStatus::Updated { binary_path } => Some(Content { @@ -403,7 +412,7 @@ impl ActivityIndicator { let reload = workspace::Reload { binary_path: Some(binary_path.clone()), }; - move |_, cx| workspace::reload(&reload, cx) + move |_, _, cx| workspace::reload(&reload, cx) })), }), AutoUpdateStatus::Errored => Some(Content { @@ -413,8 +422,8 @@ impl ActivityIndicator { .into_any_element(), ), message: "Auto update failed".to_string(), - on_click: Some(Arc::new(|this, cx| { - this.dismiss_error_message(&DismissErrorMessage, cx) + on_click: Some(Arc::new(|this, window, cx| { + this.dismiss_error_message(&DismissErrorMessage, window, cx) })), }), AutoUpdateStatus::Idle => None, @@ -432,8 +441,8 @@ impl ActivityIndicator { .into_any_element(), ), message: format!("Updating {extension_id} extension…"), - on_click: Some(Arc::new(|this, cx| { - this.dismiss_error_message(&DismissErrorMessage, cx) + on_click: Some(Arc::new(|this, window, cx| { + this.dismiss_error_message(&DismissErrorMessage, window, cx) })), }); } @@ -442,8 +451,12 @@ impl ActivityIndicator { None } - fn toggle_language_server_work_context_menu(&mut self, cx: &mut ViewContext) { - self.context_menu_handle.toggle(cx); + fn toggle_language_server_work_context_menu( + &mut self, + window: &mut Window, + cx: &mut Context, + ) { + self.context_menu_handle.toggle(window, cx); } } @@ -452,7 +465,7 @@ impl EventEmitter for ActivityIndicator {} const MAX_MESSAGE_LEN: usize = 50; impl Render for ActivityIndicator { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { let result = h_flex() .id("activity-indicator") .on_action(cx.listener(Self::show_error_message)) @@ -460,7 +473,7 @@ impl Render for ActivityIndicator { let Some(content) = self.content_to_render(cx) else { return result; }; - let this = cx.view().downgrade(); + let this = cx.model().downgrade(); let truncate_content = content.message.len() > MAX_MESSAGE_LEN; result.gap_2().child( PopoverMenu::new("activity-indicator-popover") @@ -480,24 +493,24 @@ impl Render for ActivityIndicator { )) .size(LabelSize::Small), ) - .tooltip(move |cx| Tooltip::text(&content.message, cx)) + .tooltip(Tooltip::text(content.message)) } else { button.child(Label::new(content.message).size(LabelSize::Small)) } }) .when_some(content.on_click, |this, handler| { - this.on_click(cx.listener(move |this, _, cx| { - handler(this, cx); + this.on_click(cx.listener(move |this, _, window, cx| { + handler(this, window, cx); })) .cursor(CursorStyle::PointingHand) }), ), ) .anchor(gpui::Corner::BottomLeft) - .menu(move |cx| { + .menu(move |window, cx| { let strong_this = this.upgrade()?; let mut has_work = false; - let menu = ContextMenu::build(cx, |mut menu, cx| { + let menu = ContextMenu::build(window, cx, |mut menu, _, cx| { for work in strong_this.read(cx).pending_language_server_work(cx) { has_work = true; let this = this.clone(); @@ -513,7 +526,7 @@ impl Render for ActivityIndicator { let token = work.progress_token.to_string(); let title = SharedString::from(title); menu = menu.custom_entry( - move |_| { + move |_, _| { h_flex() .w_full() .justify_between() @@ -521,7 +534,7 @@ impl Render for ActivityIndicator { .child(Icon::new(IconName::XCircle)) .into_any_element() }, - move |cx| { + move |_, cx| { this.update(cx, |this, cx| { this.project.update(cx, |project, cx| { project.cancel_language_server_work( @@ -554,5 +567,11 @@ impl Render for ActivityIndicator { } impl StatusItemView for ActivityIndicator { - fn set_active_pane_item(&mut self, _: Option<&dyn ItemHandle>, _: &mut ViewContext) {} + fn set_active_pane_item( + &mut self, + _: Option<&dyn ItemHandle>, + _window: &mut Window, + _: &mut Context, + ) { + } } diff --git a/crates/anthropic/src/anthropic.rs b/crates/anthropic/src/anthropic.rs index 1e0fdac11c..28e306d314 100644 --- a/crates/anthropic/src/anthropic.rs +++ b/crates/anthropic/src/anthropic.rs @@ -2,7 +2,7 @@ mod supported_countries; use std::{pin::Pin, str::FromStr}; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, Context as _, Result}; use chrono::{DateTime, Utc}; use futures::{io::BufReader, stream::BoxStream, AsyncBufReadExt, AsyncReadExt, Stream, StreamExt}; use http_client::http::{HeaderMap, HeaderValue}; diff --git a/crates/assets/src/assets.rs b/crates/assets/src/assets.rs index ee990085f6..8f8831269b 100644 --- a/crates/assets/src/assets.rs +++ b/crates/assets/src/assets.rs @@ -1,7 +1,7 @@ // This crate was essentially pulled out verbatim from main `zed` crate to avoid having to run RustEmbed macro whenever zed has to be rebuilt. It saves a second or two on an incremental build. use anyhow::anyhow; -use gpui::{AppContext, AssetSource, Result, SharedString}; +use gpui::{App, AssetSource, Result, SharedString}; use rust_embed::RustEmbed; #[derive(RustEmbed)] @@ -39,7 +39,7 @@ impl AssetSource for Assets { impl Assets { /// Populate the [`TextSystem`] of the given [`AppContext`] with all `.ttf` fonts in the `fonts` directory. - pub fn load_fonts(&self, cx: &AppContext) -> gpui::Result<()> { + pub fn load_fonts(&self, cx: &App) -> gpui::Result<()> { let font_paths = self.list("fonts")?; let mut embedded_fonts = Vec::new(); for font_path in font_paths { @@ -55,7 +55,7 @@ impl Assets { cx.text_system().add_fonts(embedded_fonts) } - pub fn load_test_fonts(&self, cx: &AppContext) { + pub fn load_test_fonts(&self, cx: &App) { cx.text_system() .add_fonts(vec![self .load("fonts/plex-mono/ZedPlexMono-Regular.ttf") diff --git a/crates/assistant/src/assistant.rs b/crates/assistant/src/assistant.rs index 7d291e0643..7817c958b3 100644 --- a/crates/assistant/src/assistant.rs +++ b/crates/assistant/src/assistant.rs @@ -15,7 +15,7 @@ use client::Client; use command_palette_hooks::CommandPaletteFilter; use feature_flags::FeatureFlagAppExt; use fs::Fs; -use gpui::{actions, AppContext, Global, UpdateGlobal}; +use gpui::{actions, App, Global, UpdateGlobal}; use language_model::{ LanguageModelId, LanguageModelProviderId, LanguageModelRegistry, LanguageModelResponseMessage, }; @@ -67,7 +67,7 @@ impl Global for Assistant {} impl Assistant { const NAMESPACE: &'static str = "assistant"; - fn set_enabled(&mut self, enabled: bool, cx: &mut AppContext) { + fn set_enabled(&mut self, enabled: bool, cx: &mut App) { if self.enabled == enabled { return; } @@ -92,7 +92,7 @@ pub fn init( fs: Arc, client: Arc, prompt_builder: Arc, - cx: &mut AppContext, + cx: &mut App, ) { cx.set_global(Assistant::default()); AssistantSettings::register(cx); @@ -165,7 +165,7 @@ pub fn init( .detach(); } -fn init_language_model_settings(cx: &mut AppContext) { +fn init_language_model_settings(cx: &mut App) { update_active_language_model_from_settings(cx); cx.observe_global::(update_active_language_model_from_settings) @@ -184,7 +184,7 @@ fn init_language_model_settings(cx: &mut AppContext) { .detach(); } -fn update_active_language_model_from_settings(cx: &mut AppContext) { +fn update_active_language_model_from_settings(cx: &mut App) { let settings = AssistantSettings::get_global(cx); let provider_name = LanguageModelProviderId::from(settings.default_model.provider.clone()); let model_id = LanguageModelId::from(settings.default_model.model.clone()); @@ -204,7 +204,7 @@ fn update_active_language_model_from_settings(cx: &mut AppContext) { }); } -fn register_slash_commands(prompt_builder: Option>, cx: &mut AppContext) { +fn register_slash_commands(prompt_builder: Option>, cx: &mut App) { let slash_command_registry = SlashCommandRegistry::global(cx); slash_command_registry.register_command(assistant_slash_commands::FileSlashCommand, true); @@ -278,7 +278,7 @@ fn register_slash_commands(prompt_builder: Option>, cx: &mut .detach(); } -fn update_slash_commands_from_settings(cx: &mut AppContext) { +fn update_slash_commands_from_settings(cx: &mut App) { let slash_command_registry = SlashCommandRegistry::global(cx); let settings = SlashCommandSettings::get_global(cx); diff --git a/crates/assistant/src/assistant_configuration.rs b/crates/assistant/src/assistant_configuration.rs index e4756e1e86..fdff897752 100644 --- a/crates/assistant/src/assistant_configuration.rs +++ b/crates/assistant/src/assistant_configuration.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use collections::HashMap; -use gpui::{canvas, AnyView, AppContext, EventEmitter, FocusHandle, FocusableView, Subscription}; +use gpui::{canvas, AnyView, App, EventEmitter, FocusHandle, Focusable, Subscription}; use language_model::{LanguageModelProvider, LanguageModelProviderId, LanguageModelRegistry}; use ui::{prelude::*, ElevationIndex}; use workspace::Item; @@ -13,16 +13,17 @@ pub struct ConfigurationView { } impl ConfigurationView { - pub fn new(cx: &mut ViewContext) -> Self { + pub fn new(window: &mut Window, cx: &mut Context) -> Self { let focus_handle = cx.focus_handle(); - let registry_subscription = cx.subscribe( + let registry_subscription = cx.subscribe_in( &LanguageModelRegistry::global(cx), - |this, _, event: &language_model::Event, cx| match event { + window, + |this, _, event: &language_model::Event, window, cx| match event { language_model::Event::AddedProvider(provider_id) => { let provider = LanguageModelRegistry::read_global(cx).provider(provider_id); if let Some(provider) = provider { - this.add_configuration_view(&provider, cx); + this.add_configuration_view(&provider, window, cx); } } language_model::Event::RemovedProvider(provider_id) => { @@ -37,14 +38,14 @@ impl ConfigurationView { configuration_views: HashMap::default(), _registry_subscription: registry_subscription, }; - this.build_configuration_views(cx); + this.build_configuration_views(window, cx); this } - fn build_configuration_views(&mut self, cx: &mut ViewContext) { + fn build_configuration_views(&mut self, window: &mut Window, cx: &mut Context) { let providers = LanguageModelRegistry::read_global(cx).providers(); for provider in providers { - self.add_configuration_view(&provider, cx); + self.add_configuration_view(&provider, window, cx); } } @@ -55,9 +56,10 @@ impl ConfigurationView { fn add_configuration_view( &mut self, provider: &Arc, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - let configuration_view = provider.configuration_view(cx); + let configuration_view = provider.configuration_view(window, cx); self.configuration_views .insert(provider.id(), configuration_view); } @@ -65,7 +67,7 @@ impl ConfigurationView { fn render_provider_view( &mut self, provider: &Arc, - cx: &mut ViewContext, + cx: &mut Context, ) -> Div { let provider_id = provider.id().0.clone(); let provider_name = provider.name().0.clone(); @@ -73,7 +75,7 @@ impl ConfigurationView { let open_new_context = cx.listener({ let provider = provider.clone(); - move |_, _, cx| { + move |_, _, _window, cx| { cx.emit(ConfigurationViewEvent::NewProviderContextEditor( provider.clone(), )) @@ -123,7 +125,7 @@ impl ConfigurationView { } impl Render for ConfigurationView { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { let providers = LanguageModelRegistry::read_global(cx).providers(); let provider_views = providers .into_iter() @@ -163,12 +165,12 @@ impl Render for ConfigurationView { // We use a canvas here to get scrolling to work in the ConfigurationView. It's a workaround // because we couldn't the element to take up the size of the parent. canvas( - move |bounds, cx| { - element.prepaint_as_root(bounds.origin, bounds.size.into(), cx); + move |bounds, window, cx| { + element.prepaint_as_root(bounds.origin, bounds.size.into(), window, cx); element }, - |_, mut element, cx| { - element.paint(cx); + |_, mut element, window, cx| { + element.paint(window, cx); }, ) .flex_1() @@ -182,8 +184,8 @@ pub enum ConfigurationViewEvent { impl EventEmitter for ConfigurationView {} -impl FocusableView for ConfigurationView { - fn focus_handle(&self, _: &AppContext) -> FocusHandle { +impl Focusable for ConfigurationView { + fn focus_handle(&self, _: &App) -> FocusHandle { self.focus_handle.clone() } } @@ -191,7 +193,7 @@ impl FocusableView for ConfigurationView { impl Item for ConfigurationView { type Event = ConfigurationViewEvent; - fn tab_content_text(&self, _cx: &WindowContext) -> Option { + fn tab_content_text(&self, _window: &Window, _cx: &App) -> Option { Some("Configuration".into()) } } diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index e5c3c76180..bcd55b7a26 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -4,7 +4,7 @@ use crate::{ }; use anyhow::{anyhow, Result}; use assistant_context_editor::{ - make_lsp_adapter_delegate, AssistantPanelDelegate, Context, ContextEditor, + make_lsp_adapter_delegate, AssistantContext, AssistantPanelDelegate, ContextEditor, ContextEditorToolbarItem, ContextEditorToolbarItemEvent, ContextHistory, ContextId, ContextStore, ContextStoreEvent, InsertDraggedFiles, SlashCommandCompletionProvider, ToggleModelSelector, DEFAULT_TAB_TITLE, @@ -16,9 +16,9 @@ use client::{proto, Client, Status}; use editor::{Editor, EditorEvent}; use fs::Fs; use gpui::{ - prelude::*, Action, AppContext, AsyncWindowContext, EventEmitter, ExternalPaths, FocusHandle, - FocusableView, InteractiveElement, IntoElement, Model, ParentElement, Pixels, Render, Styled, - Subscription, Task, UpdateGlobal, View, WeakView, + prelude::*, Action, App, AsyncWindowContext, Entity, EventEmitter, ExternalPaths, FocusHandle, + Focusable, InteractiveElement, IntoElement, ParentElement, Pixels, Render, Styled, + Subscription, Task, UpdateGlobal, WeakEntity, }; use language::LanguageRegistry; use language_model::{LanguageModelProviderId, LanguageModelRegistry, ZED_CLOUD_PROVIDER_ID}; @@ -39,10 +39,10 @@ use workspace::{ }; use zed_actions::assistant::{DeployPromptLibrary, InlineAssist, ToggleFocus}; -pub fn init(cx: &mut AppContext) { +pub fn init(cx: &mut App) { workspace::FollowableViewRegistry::register::(cx); - cx.observe_new_views( - |workspace: &mut Workspace, _cx: &mut ViewContext| { + cx.observe_new( + |workspace: &mut Workspace, _window, _cx: &mut Context| { workspace .register_action(ContextEditor::quote_selection) .register_action(ContextEditor::insert_selection) @@ -55,8 +55,8 @@ pub fn init(cx: &mut AppContext) { ) .detach(); - cx.observe_new_views( - |terminal_panel: &mut TerminalPanel, cx: &mut ViewContext| { + cx.observe_new( + |terminal_panel: &mut TerminalPanel, _, cx: &mut Context| { let settings = AssistantSettings::get_global(cx); terminal_panel.set_assistant_enabled(settings.enabled, cx); }, @@ -69,17 +69,17 @@ pub enum AssistantPanelEvent { } pub struct AssistantPanel { - pane: View, - workspace: WeakView, + pane: Entity, + workspace: WeakEntity, width: Option, height: Option, - project: Model, - context_store: Model, + project: Entity, + context_store: Entity, languages: Arc, fs: Arc, subscriptions: Vec, model_selector_menu_handle: PopoverMenuHandle, - model_summary_editor: View, + model_summary_editor: Entity, authenticate_provider_task: Option<(LanguageModelProviderId, Task<()>)>, configuration_subscription: Option, client_status: Option, @@ -88,16 +88,16 @@ pub struct AssistantPanel { } enum InlineAssistTarget { - Editor(View, bool), - Terminal(View), + Editor(Entity, bool), + Terminal(Entity), } impl AssistantPanel { pub fn load( - workspace: WeakView, + workspace: WeakEntity, prompt_builder: Arc, cx: AsyncWindowContext, - ) -> Task>> { + ) -> Task>> { cx.spawn(|mut cx| async move { let slash_commands = Arc::new(SlashCommandWorkingSet::default()); let tools = Arc::new(ToolWorkingSet::default()); @@ -108,41 +108,44 @@ impl AssistantPanel { })? .await?; - workspace.update(&mut cx, |workspace, cx| { + workspace.update_in(&mut cx, |workspace, window, cx| { // TODO: deserialize state. - cx.new_view(|cx| Self::new(workspace, context_store, cx)) + cx.new(|cx| Self::new(workspace, context_store, window, cx)) }) }) } fn new( workspace: &Workspace, - context_store: Model, - cx: &mut ViewContext, + context_store: Entity, + window: &mut Window, + cx: &mut Context, ) -> Self { let model_selector_menu_handle = PopoverMenuHandle::default(); - let model_summary_editor = cx.new_view(Editor::single_line); - let context_editor_toolbar = cx.new_view(|cx| { + let model_summary_editor = cx.new(|cx| Editor::single_line(window, cx)); + let context_editor_toolbar = cx.new(|cx| { ContextEditorToolbarItem::new( workspace, model_selector_menu_handle.clone(), model_summary_editor.clone(), + window, cx, ) }); - let pane = cx.new_view(|cx| { + let pane = cx.new(|cx| { let mut pane = Pane::new( workspace.weak_handle(), workspace.project().clone(), Default::default(), None, NewContext.boxed_clone(), + window, cx, ); let project = workspace.project().clone(); - pane.set_custom_drop_handle(cx, move |_, dropped_item, cx| { + pane.set_custom_drop_handle(cx, move |_, dropped_item, window, cx| { let action = maybe!({ if project.read(cx).is_local() { if let Some(paths) = dropped_item.downcast_ref::() { @@ -152,7 +155,7 @@ impl AssistantPanel { let project_paths = if let Some(tab) = dropped_item.downcast_ref::() { - if &tab.pane == cx.view() { + if tab.pane == cx.model() { return None; } let item = tab.pane.read(cx).item_for_index(tab.ix); @@ -192,7 +195,7 @@ impl AssistantPanel { }); if let Some(action) = action { - cx.dispatch_action(action.boxed_clone()); + window.dispatch_action(action.boxed_clone(), cx); } ControlFlow::Break(()) @@ -200,25 +203,26 @@ impl AssistantPanel { pane.set_can_navigate(true, cx); pane.display_nav_history_buttons(None); - pane.set_should_display_tab_bar(|_| true); - pane.set_render_tab_bar_buttons(cx, move |pane, cx| { + pane.set_should_display_tab_bar(|_, _| true); + pane.set_render_tab_bar_buttons(cx, move |pane, _window, cx| { let focus_handle = pane.focus_handle(cx); let left_children = IconButton::new("history", IconName::HistoryRerun) .icon_size(IconSize::Small) .on_click(cx.listener({ let focus_handle = focus_handle.clone(); - move |_, _, cx| { - focus_handle.focus(cx); - cx.dispatch_action(DeployHistory.boxed_clone()) + move |_, _, window, cx| { + focus_handle.focus(window); + window.dispatch_action(DeployHistory.boxed_clone(), cx) } })) .tooltip({ let focus_handle = focus_handle.clone(); - move |cx| { + move |window, cx| { Tooltip::for_action_in( "Open History", &DeployHistory, &focus_handle, + window, cx, ) } @@ -227,19 +231,23 @@ impl AssistantPanel { pane.active_item() .map_or(false, |item| item.downcast::().is_some()), ); - let _pane = cx.view().clone(); + let _pane = cx.model().clone(); let right_children = h_flex() .gap(DynamicSpacing::Base02.rems(cx)) .child( IconButton::new("new-chat", IconName::Plus) .icon_size(IconSize::Small) - .on_click( - cx.listener(|_, _, cx| { - cx.dispatch_action(NewContext.boxed_clone()) - }), - ) - .tooltip(move |cx| { - Tooltip::for_action_in("New Chat", &NewContext, &focus_handle, cx) + .on_click(cx.listener(|_, _, window, cx| { + window.dispatch_action(NewContext.boxed_clone(), cx) + })) + .tooltip(move |window, cx| { + Tooltip::for_action_in( + "New Chat", + &NewContext, + &focus_handle, + window, + cx, + ) }), ) .child( @@ -247,16 +255,16 @@ impl AssistantPanel { .trigger( IconButton::new("menu", IconName::EllipsisVertical) .icon_size(IconSize::Small) - .tooltip(|cx| Tooltip::text("Toggle Assistant Menu", cx)), + .tooltip(Tooltip::text("Toggle Assistant Menu")), ) - .menu(move |cx| { + .menu(move |window, cx| { let zoom_label = if _pane.read(cx).is_zoomed() { "Zoom Out" } else { "Zoom In" }; let focus_handle = _pane.focus_handle(cx); - Some(ContextMenu::build(cx, move |menu, _| { + Some(ContextMenu::build(window, cx, move |menu, _, _| { menu.context(focus_handle.clone()) .action("New Chat", Box::new(NewContext)) .action("History", Box::new(DeployHistory)) @@ -272,37 +280,38 @@ impl AssistantPanel { (Some(left_children.into_any_element()), right_children) }); pane.toolbar().update(cx, |toolbar, cx| { - toolbar.add_item(context_editor_toolbar.clone(), cx); - toolbar.add_item(cx.new_view(BufferSearchBar::new), cx) + toolbar.add_item(context_editor_toolbar.clone(), window, cx); + toolbar.add_item(cx.new(|cx| BufferSearchBar::new(window, cx)), window, cx) }); pane }); let subscriptions = vec![ cx.observe(&pane, |_, _, cx| cx.notify()), - cx.subscribe(&pane, Self::handle_pane_event), + cx.subscribe_in(&pane, window, Self::handle_pane_event), cx.subscribe(&context_editor_toolbar, Self::handle_toolbar_event), cx.subscribe(&model_summary_editor, Self::handle_summary_editor_event), - cx.subscribe(&context_store, Self::handle_context_store_event), - cx.subscribe( + cx.subscribe_in(&context_store, window, Self::handle_context_store_event), + cx.subscribe_in( &LanguageModelRegistry::global(cx), - |this, _, event: &language_model::Event, cx| match event { + window, + |this, _, event: &language_model::Event, window, cx| match event { language_model::Event::ActiveModelChanged => { - this.completion_provider_changed(cx); + this.completion_provider_changed(window, cx); } language_model::Event::ProviderStateChanged => { - this.ensure_authenticated(cx); + this.ensure_authenticated(window, cx); cx.notify() } language_model::Event::AddedProvider(_) | language_model::Event::RemovedProvider(_) => { - this.ensure_authenticated(cx); + this.ensure_authenticated(window, cx); } }, ), ]; - let watch_client_status = Self::watch_client_status(workspace.client().clone(), cx); + let watch_client_status = Self::watch_client_status(workspace.client().clone(), window, cx); let mut this = Self { pane, @@ -322,27 +331,32 @@ impl AssistantPanel { watch_client_status: Some(watch_client_status), show_zed_ai_notice: false, }; - this.new_context(cx); + this.new_context(window, cx); this } pub fn toggle_focus( workspace: &mut Workspace, _: &ToggleFocus, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let settings = AssistantSettings::get_global(cx); if !settings.enabled { return; } - workspace.toggle_panel_focus::(cx); + workspace.toggle_panel_focus::(window, cx); } - fn watch_client_status(client: Arc, cx: &mut ViewContext) -> Task<()> { + fn watch_client_status( + client: Arc, + window: &mut Window, + cx: &mut Context, + ) -> Task<()> { let mut status_rx = client.status(); - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { while let Some(status) = status_rx.next().await { this.update(&mut cx, |this, cx| { if this.client_status.is_none() @@ -363,9 +377,10 @@ impl AssistantPanel { fn handle_pane_event( &mut self, - pane: View, + pane: &Entity, event: &pane::Event, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let update_model_summary = match event { pane::Event::Remove { .. } => { @@ -384,7 +399,7 @@ impl AssistantPanel { pane::Event::AddItem { item } => { self.workspace .update(cx, |workspace, cx| { - item.added_to_pane(workspace, self.pane.clone(), cx) + item.added_to_pane(workspace, self.pane.clone(), window, cx) }) .ok(); true @@ -394,7 +409,7 @@ impl AssistantPanel { if *local { self.workspace .update(cx, |workspace, cx| { - workspace.unfollow_in_pane(&pane, cx); + workspace.unfollow_in_pane(&pane, window, cx); }) .ok(); } @@ -422,16 +437,16 @@ impl AssistantPanel { if update_model_summary { if let Some(editor) = self.active_context_editor(cx) { - self.show_updated_summary(&editor, cx) + self.show_updated_summary(&editor, window, cx) } } } fn handle_summary_editor_event( &mut self, - model_summary_editor: View, + model_summary_editor: Entity, event: &EditorEvent, - cx: &mut ViewContext, + cx: &mut Context, ) { if matches!(event, EditorEvent::Edited { .. }) { if let Some(context_editor) = self.active_context_editor(cx) { @@ -450,11 +465,7 @@ impl AssistantPanel { } } - fn update_zed_ai_notice_visibility( - &mut self, - client_status: Status, - cx: &mut ViewContext, - ) { + fn update_zed_ai_notice_visibility(&mut self, client_status: Status, cx: &mut Context) { let active_provider = LanguageModelRegistry::read_global(cx).active_provider(); // If we're signed out and don't have a provider configured, or we're signed-out AND Zed.dev is @@ -468,9 +479,9 @@ impl AssistantPanel { fn handle_toolbar_event( &mut self, - _: View, + _: Entity, _: &ContextEditorToolbarItemEvent, - cx: &mut ViewContext, + cx: &mut Context, ) { if let Some(context_editor) = self.active_context_editor(cx) { context_editor.update(cx, |context_editor, cx| { @@ -483,9 +494,10 @@ impl AssistantPanel { fn handle_context_store_event( &mut self, - _context_store: Model, + _context_store: &Entity, event: &ContextStoreEvent, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let ContextStoreEvent::ContextCreated(context_id) = event; let Some(context) = self @@ -500,23 +512,24 @@ impl AssistantPanel { .log_err() .flatten(); - let editor = cx.new_view(|cx| { + let editor = cx.new(|cx| { let mut editor = ContextEditor::for_context( context, self.fs.clone(), self.workspace.clone(), self.project.clone(), lsp_adapter_delegate, + window, cx, ); - editor.insert_default_prompt(cx); + editor.insert_default_prompt(window, cx); editor }); - self.show_context(editor.clone(), cx); + self.show_context(editor.clone(), window, cx); } - fn completion_provider_changed(&mut self, cx: &mut ViewContext) { + fn completion_provider_changed(&mut self, window: &mut Window, cx: &mut Context) { if let Some(editor) = self.active_context_editor(cx) { editor.update(cx, |active_context, cx| { active_context @@ -540,7 +553,7 @@ impl AssistantPanel { }) { self.authenticate_provider_task = None; - self.ensure_authenticated(cx); + self.ensure_authenticated(window, cx); } if let Some(status) = self.client_status { @@ -548,7 +561,7 @@ impl AssistantPanel { } } - fn ensure_authenticated(&mut self, cx: &mut ViewContext) { + fn ensure_authenticated(&mut self, window: &mut Window, cx: &mut Context) { if self.is_authenticated(cx) { return; } @@ -562,7 +575,7 @@ impl AssistantPanel { if self.authenticate_provider_task.is_none() { self.authenticate_provider_task = Some(( provider.id(), - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { if let Some(future) = load_credentials { let _ = future.await; } @@ -578,7 +591,8 @@ impl AssistantPanel { pub fn inline_assist( workspace: &mut Workspace, action: &InlineAssist, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let settings = AssistantSettings::get_global(cx); if !settings.enabled { @@ -590,7 +604,7 @@ impl AssistantPanel { }; let Some(inline_assist_target) = - Self::resolve_inline_assist_target(workspace, &assistant_panel, cx) + Self::resolve_inline_assist_target(workspace, &assistant_panel, window, cx) else { return; }; @@ -603,9 +617,10 @@ impl AssistantPanel { InlineAssistant::update_global(cx, |assistant, cx| { assistant.assist( &active_editor, - Some(cx.view().downgrade()), + Some(cx.model().downgrade()), include_context.then_some(&assistant_panel), initial_prompt, + window, cx, ) }) @@ -614,9 +629,10 @@ impl AssistantPanel { TerminalInlineAssistant::update_global(cx, |assistant, cx| { assistant.assist( &active_terminal, - Some(cx.view().downgrade()), + Some(cx.model().downgrade()), Some(&assistant_panel), initial_prompt, + window, cx, ) }) @@ -624,7 +640,7 @@ impl AssistantPanel { } } else { let assistant_panel = assistant_panel.downgrade(); - cx.spawn(|workspace, mut cx| async move { + cx.spawn_in(window, |workspace, mut cx| async move { let Some(task) = assistant_panel.update(&mut cx, |assistant, cx| assistant.authenticate(cx))? else { @@ -639,15 +655,17 @@ impl AssistantPanel { .ok(); if let Some(answer) = answer { if answer == 0 { - cx.update(|cx| cx.dispatch_action(Box::new(ShowConfiguration))) - .ok(); + cx.update(|window, cx| { + window.dispatch_action(Box::new(ShowConfiguration), cx) + }) + .ok(); } } return Ok(()); }; task.await?; if assistant_panel.update(&mut cx, |panel, cx| panel.is_authenticated(cx))? { - cx.update(|cx| match inline_assist_target { + cx.update(|window, cx| match inline_assist_target { InlineAssistTarget::Editor(active_editor, include_context) => { let assistant_panel = if include_context { assistant_panel.upgrade() @@ -660,6 +678,7 @@ impl AssistantPanel { Some(workspace), assistant_panel.as_ref(), initial_prompt, + window, cx, ) }) @@ -671,14 +690,15 @@ impl AssistantPanel { Some(workspace), assistant_panel.upgrade().as_ref(), initial_prompt, + window, cx, ) }) } })? } else { - workspace.update(&mut cx, |workspace, cx| { - workspace.focus_panel::(cx) + workspace.update_in(&mut cx, |workspace, window, cx| { + workspace.focus_panel::(window, cx) })?; } @@ -690,14 +710,15 @@ impl AssistantPanel { fn resolve_inline_assist_target( workspace: &mut Workspace, - assistant_panel: &View, - cx: &mut WindowContext, + assistant_panel: &Entity, + window: &mut Window, + cx: &mut App, ) -> Option { if let Some(terminal_panel) = workspace.panel::(cx) { if terminal_panel .read(cx) .focus_handle(cx) - .contains_focused(cx) + .contains_focused(window, cx) { if let Some(terminal_view) = terminal_panel.read(cx).pane().and_then(|pane| { pane.read(cx) @@ -714,7 +735,7 @@ impl AssistantPanel { .active_context_editor(cx) .and_then(|editor| { let editor = &editor.read(cx).editor().clone(); - if editor.read(cx).is_focused(cx) { + if editor.read(cx).is_focused(window) { Some(editor.clone()) } else { None @@ -741,33 +762,38 @@ impl AssistantPanel { pub fn create_new_context( workspace: &mut Workspace, _: &NewContext, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if let Some(panel) = workspace.panel::(cx) { let did_create_context = panel .update(cx, |panel, cx| { - panel.new_context(cx)?; + panel.new_context(window, cx)?; Some(()) }) .is_some(); if did_create_context { - ContextEditor::quote_selection(workspace, &Default::default(), cx); + ContextEditor::quote_selection(workspace, &Default::default(), window, cx); } } } - pub fn new_context(&mut self, cx: &mut ViewContext) -> Option> { + pub fn new_context( + &mut self, + window: &mut Window, + cx: &mut Context, + ) -> Option> { let project = self.project.read(cx); if project.is_via_collab() { let task = self .context_store .update(cx, |store, cx| store.create_remote_context(cx)); - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { let context = task.await?; - this.update(&mut cx, |this, cx| { + this.update_in(&mut cx, |this, window, cx| { let workspace = this.workspace.clone(); let project = this.project.clone(); let lsp_adapter_delegate = @@ -776,18 +802,19 @@ impl AssistantPanel { let fs = this.fs.clone(); let project = this.project.clone(); - let editor = cx.new_view(|cx| { + let editor = cx.new(|cx| { ContextEditor::for_context( context, fs, workspace, project, lsp_adapter_delegate, + window, cx, ) }); - this.show_context(editor, cx); + this.show_context(editor, window, cx); anyhow::Ok(()) })??; @@ -803,25 +830,26 @@ impl AssistantPanel { .log_err() .flatten(); - let editor = cx.new_view(|cx| { + let editor = cx.new(|cx| { let mut editor = ContextEditor::for_context( context, self.fs.clone(), self.workspace.clone(), self.project.clone(), lsp_adapter_delegate, + window, cx, ); - editor.insert_default_prompt(cx); + editor.insert_default_prompt(window, cx); editor }); - self.show_context(editor.clone(), cx); + self.show_context(editor.clone(), window, cx); let workspace = self.workspace.clone(); - cx.spawn(move |_, mut cx| async move { + cx.spawn_in(window, move |_, mut cx| async move { workspace - .update(&mut cx, |workspace, cx| { - workspace.focus_panel::(cx); + .update_in(&mut cx, |workspace, window, cx| { + workspace.focus_panel::(window, cx); }) .ok(); }) @@ -830,19 +858,34 @@ impl AssistantPanel { } } - fn show_context(&mut self, context_editor: View, cx: &mut ViewContext) { - let focus = self.focus_handle(cx).contains_focused(cx); + fn show_context( + &mut self, + context_editor: Entity, + window: &mut Window, + cx: &mut Context, + ) { + let focus = self.focus_handle(cx).contains_focused(window, cx); let prev_len = self.pane.read(cx).items_len(); self.pane.update(cx, |pane, cx| { - pane.add_item(Box::new(context_editor.clone()), focus, focus, None, cx) + pane.add_item( + Box::new(context_editor.clone()), + focus, + focus, + None, + window, + cx, + ) }); if prev_len != self.pane.read(cx).items_len() { - self.subscriptions - .push(cx.subscribe(&context_editor, Self::handle_context_editor_event)); + self.subscriptions.push(cx.subscribe_in( + &context_editor, + window, + Self::handle_context_editor_event, + )); } - self.show_updated_summary(&context_editor, cx); + self.show_updated_summary(&context_editor, window, cx); cx.emit(AssistantPanelEvent::ContextEdited); cx.notify(); @@ -850,14 +893,15 @@ impl AssistantPanel { fn show_updated_summary( &self, - context_editor: &View, - cx: &mut ViewContext, + context_editor: &Entity, + window: &mut Window, + cx: &mut Context, ) { context_editor.update(cx, |context_editor, cx| { let new_summary = context_editor.title(cx).to_string(); self.model_summary_editor.update(cx, |summary_editor, cx| { if summary_editor.text(cx) != new_summary { - summary_editor.set_text(new_summary, cx); + summary_editor.set_text(new_summary, window, cx); } }); }); @@ -865,13 +909,14 @@ impl AssistantPanel { fn handle_context_editor_event( &mut self, - context_editor: View, + context_editor: &Entity, event: &EditorEvent, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { match event { EditorEvent::TitleChanged => { - self.show_updated_summary(&context_editor, cx); + self.show_updated_summary(&context_editor, window, cx); cx.notify() } EditorEvent::Edited { .. } => { @@ -896,22 +941,23 @@ impl AssistantPanel { fn show_configuration( workspace: &mut Workspace, _: &ShowConfiguration, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let Some(panel) = workspace.panel::(cx) else { return; }; - if !panel.focus_handle(cx).contains_focused(cx) { - workspace.toggle_panel_focus::(cx); + if !panel.focus_handle(cx).contains_focused(window, cx) { + workspace.toggle_panel_focus::(window, cx); } panel.update(cx, |this, cx| { - this.show_configuration_tab(cx); + this.show_configuration_tab(window, cx); }) } - fn show_configuration_tab(&mut self, cx: &mut ViewContext) { + fn show_configuration_tab(&mut self, window: &mut Window, cx: &mut Context) { let configuration_item_ix = self .pane .read(cx) @@ -920,13 +966,14 @@ impl AssistantPanel { if let Some(configuration_item_ix) = configuration_item_ix { self.pane.update(cx, |pane, cx| { - pane.activate_item(configuration_item_ix, true, true, cx); + pane.activate_item(configuration_item_ix, true, true, window, cx); }); } else { - let configuration = cx.new_view(ConfigurationView::new); - self.configuration_subscription = Some(cx.subscribe( + let configuration = cx.new(|cx| ConfigurationView::new(window, cx)); + self.configuration_subscription = Some(cx.subscribe_in( &configuration, - |this, _, event: &ConfigurationViewEvent, cx| match event { + window, + |this, _, event: &ConfigurationViewEvent, window, cx| match event { ConfigurationViewEvent::NewProviderContextEditor(provider) => { if LanguageModelRegistry::read_global(cx) .active_provider() @@ -941,17 +988,17 @@ impl AssistantPanel { } } - this.new_context(cx); + this.new_context(window, cx); } }, )); self.pane.update(cx, |pane, cx| { - pane.add_item(Box::new(configuration), true, true, None, cx); + pane.add_item(Box::new(configuration), true, true, None, window, cx); }); } } - fn deploy_history(&mut self, _: &DeployHistory, cx: &mut ViewContext) { + fn deploy_history(&mut self, _: &DeployHistory, window: &mut Window, cx: &mut Context) { let history_item_ix = self .pane .read(cx) @@ -960,24 +1007,30 @@ impl AssistantPanel { if let Some(history_item_ix) = history_item_ix { self.pane.update(cx, |pane, cx| { - pane.activate_item(history_item_ix, true, true, cx); + pane.activate_item(history_item_ix, true, true, window, cx); }); } else { - let history = cx.new_view(|cx| { + let history = cx.new(|cx| { ContextHistory::new( self.project.clone(), self.context_store.clone(), self.workspace.clone(), + window, cx, ) }); self.pane.update(cx, |pane, cx| { - pane.add_item(Box::new(history), true, true, None, cx); + pane.add_item(Box::new(history), true, true, None, window, cx); }); } } - fn deploy_prompt_library(&mut self, _: &DeployPromptLibrary, cx: &mut ViewContext) { + fn deploy_prompt_library( + &mut self, + _: &DeployPromptLibrary, + _window: &mut Window, + cx: &mut Context, + ) { open_prompt_library( self.languages.clone(), Box::new(PromptLibraryInlineAssist), @@ -993,33 +1046,41 @@ impl AssistantPanel { .detach_and_log_err(cx); } - fn toggle_model_selector(&mut self, _: &ToggleModelSelector, cx: &mut ViewContext) { - self.model_selector_menu_handle.toggle(cx); + fn toggle_model_selector( + &mut self, + _: &ToggleModelSelector, + window: &mut Window, + cx: &mut Context, + ) { + self.model_selector_menu_handle.toggle(window, cx); } - pub(crate) fn active_context_editor(&self, cx: &AppContext) -> Option> { + pub(crate) fn active_context_editor(&self, cx: &App) -> Option> { self.pane .read(cx) .active_item()? .downcast::() } - pub fn active_context(&self, cx: &AppContext) -> Option> { + pub fn active_context(&self, cx: &App) -> Option> { Some(self.active_context_editor(cx)?.read(cx).context().clone()) } pub fn open_saved_context( &mut self, path: PathBuf, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { let existing_context = self.pane.read(cx).items().find_map(|item| { item.downcast::() .filter(|editor| editor.read(cx).context().read(cx).path() == Some(&path)) }); if let Some(existing_context) = existing_context { - return cx.spawn(|this, mut cx| async move { - this.update(&mut cx, |this, cx| this.show_context(existing_context, cx)) + return cx.spawn_in(window, |this, mut cx| async move { + this.update_in(&mut cx, |this, window, cx| { + this.show_context(existing_context, window, cx) + }) }); } @@ -1032,20 +1093,21 @@ impl AssistantPanel { let lsp_adapter_delegate = make_lsp_adapter_delegate(&project, cx).log_err().flatten(); - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { let context = context.await?; - this.update(&mut cx, |this, cx| { - let editor = cx.new_view(|cx| { + this.update_in(&mut cx, |this, window, cx| { + let editor = cx.new(|cx| { ContextEditor::for_context( context, fs, workspace, project, lsp_adapter_delegate, + window, cx, ) }); - this.show_context(editor, cx); + this.show_context(editor, window, cx); anyhow::Ok(()) })??; Ok(()) @@ -1055,16 +1117,17 @@ impl AssistantPanel { pub fn open_remote_context( &mut self, id: ContextId, - cx: &mut ViewContext, - ) -> Task>> { + window: &mut Window, + cx: &mut Context, + ) -> Task>> { let existing_context = self.pane.read(cx).items().find_map(|item| { item.downcast::() .filter(|editor| *editor.read(cx).context().read(cx).id() == id) }); if let Some(existing_context) = existing_context { - return cx.spawn(|this, mut cx| async move { - this.update(&mut cx, |this, cx| { - this.show_context(existing_context.clone(), cx) + return cx.spawn_in(window, |this, mut cx| async move { + this.update_in(&mut cx, |this, window, cx| { + this.show_context(existing_context.clone(), window, cx) })?; Ok(existing_context) }); @@ -1079,32 +1142,33 @@ impl AssistantPanel { .log_err() .flatten(); - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { let context = context.await?; - this.update(&mut cx, |this, cx| { - let editor = cx.new_view(|cx| { + this.update_in(&mut cx, |this, window, cx| { + let editor = cx.new(|cx| { ContextEditor::for_context( context, fs, workspace, this.project.clone(), lsp_adapter_delegate, + window, cx, ) }); - this.show_context(editor.clone(), cx); + this.show_context(editor.clone(), window, cx); anyhow::Ok(editor) })? }) } - fn is_authenticated(&mut self, cx: &mut ViewContext) -> bool { + fn is_authenticated(&mut self, cx: &mut Context) -> bool { LanguageModelRegistry::read_global(cx) .active_provider() .map_or(false, |provider| provider.is_authenticated(cx)) } - fn authenticate(&mut self, cx: &mut ViewContext) -> Option>> { + fn authenticate(&mut self, cx: &mut Context) -> Option>> { LanguageModelRegistry::read_global(cx) .active_provider() .map_or(None, |provider| Some(provider.authenticate(cx))) @@ -1113,7 +1177,8 @@ impl AssistantPanel { fn restart_context_servers( workspace: &mut Workspace, _action: &context_server::Restart, - cx: &mut ViewContext, + _: &mut Window, + cx: &mut Context, ) { let Some(assistant_panel) = workspace.panel::(cx) else { return; @@ -1130,9 +1195,9 @@ impl AssistantPanel { } impl Render for AssistantPanel { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { let mut registrar = DivRegistrar::new( - |panel, cx| { + |panel, _, cx| { panel .pane .read(cx) @@ -1148,12 +1213,12 @@ impl Render for AssistantPanel { v_flex() .key_context("AssistantPanel") .size_full() - .on_action(cx.listener(|this, _: &NewContext, cx| { - this.new_context(cx); + .on_action(cx.listener(|this, _: &NewContext, window, cx| { + this.new_context(window, cx); + })) + .on_action(cx.listener(|this, _: &ShowConfiguration, window, cx| { + this.show_configuration_tab(window, cx) })) - .on_action( - cx.listener(|this, _: &ShowConfiguration, cx| this.show_configuration_tab(cx)), - ) .on_action(cx.listener(AssistantPanel::deploy_history)) .on_action(cx.listener(AssistantPanel::deploy_prompt_library)) .on_action(cx.listener(AssistantPanel::toggle_model_selector)) @@ -1167,7 +1232,7 @@ impl Panel for AssistantPanel { "AssistantPanel" } - fn position(&self, cx: &WindowContext) -> DockPosition { + fn position(&self, _: &Window, cx: &App) -> DockPosition { match AssistantSettings::get_global(cx).dock { AssistantDockPosition::Left => DockPosition::Left, AssistantDockPosition::Bottom => DockPosition::Bottom, @@ -1179,7 +1244,7 @@ impl Panel for AssistantPanel { true } - fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext) { + fn set_position(&mut self, position: DockPosition, _: &mut Window, cx: &mut Context) { settings::update_settings_file::( self.fs.clone(), cx, @@ -1194,9 +1259,9 @@ impl Panel for AssistantPanel { ); } - fn size(&self, cx: &WindowContext) -> Pixels { + fn size(&self, window: &Window, cx: &App) -> Pixels { let settings = AssistantSettings::get_global(cx); - match self.position(cx) { + match self.position(window, cx) { DockPosition::Left | DockPosition::Right => { self.width.unwrap_or(settings.default_width) } @@ -1204,33 +1269,33 @@ impl Panel for AssistantPanel { } } - fn set_size(&mut self, size: Option, cx: &mut ViewContext) { - match self.position(cx) { + fn set_size(&mut self, size: Option, window: &mut Window, cx: &mut Context) { + match self.position(window, cx) { DockPosition::Left | DockPosition::Right => self.width = size, DockPosition::Bottom => self.height = size, } cx.notify(); } - fn is_zoomed(&self, cx: &WindowContext) -> bool { + fn is_zoomed(&self, _: &Window, cx: &App) -> bool { self.pane.read(cx).is_zoomed() } - fn set_zoomed(&mut self, zoomed: bool, cx: &mut ViewContext) { + fn set_zoomed(&mut self, zoomed: bool, _: &mut Window, cx: &mut Context) { self.pane.update(cx, |pane, cx| pane.set_zoomed(zoomed, cx)); } - fn set_active(&mut self, active: bool, cx: &mut ViewContext) { + fn set_active(&mut self, active: bool, window: &mut Window, cx: &mut Context) { if active { if self.pane.read(cx).items_len() == 0 { - self.new_context(cx); + self.new_context(window, cx); } - self.ensure_authenticated(cx); + self.ensure_authenticated(window, cx); } } - fn pane(&self) -> Option> { + fn pane(&self) -> Option> { Some(self.pane.clone()) } @@ -1238,7 +1303,7 @@ impl Panel for AssistantPanel { Some(proto::PanelId::AssistantPanel) } - fn icon(&self, cx: &WindowContext) -> Option { + fn icon(&self, _: &Window, cx: &App) -> Option { let settings = AssistantSettings::get_global(cx); if !settings.enabled || !settings.button { return None; @@ -1247,7 +1312,7 @@ impl Panel for AssistantPanel { Some(IconName::ZedAssistant) } - fn icon_tooltip(&self, _cx: &WindowContext) -> Option<&'static str> { + fn icon_tooltip(&self, _: &Window, _: &App) -> Option<&'static str> { Some("Assistant Panel") } @@ -1263,8 +1328,8 @@ impl Panel for AssistantPanel { impl EventEmitter for AssistantPanel {} impl EventEmitter for AssistantPanel {} -impl FocusableView for AssistantPanel { - fn focus_handle(&self, cx: &AppContext) -> FocusHandle { +impl Focusable for AssistantPanel { + fn focus_handle(&self, cx: &App) -> FocusHandle { self.pane.focus_handle(cx) } } @@ -1274,21 +1339,25 @@ struct PromptLibraryInlineAssist; impl prompt_library::InlineAssistDelegate for PromptLibraryInlineAssist { fn assist( &self, - prompt_editor: &View, + prompt_editor: &Entity, initial_prompt: Option, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { InlineAssistant::update_global(cx, |assistant, cx| { - assistant.assist(&prompt_editor, None, None, initial_prompt, cx) + assistant.assist(&prompt_editor, None, None, initial_prompt, window, cx) }) } fn focus_assistant_panel( &self, workspace: &mut Workspace, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> bool { - workspace.focus_panel::(cx).is_some() + workspace + .focus_panel::(window, cx) + .is_some() } } @@ -1298,8 +1367,9 @@ impl AssistantPanelDelegate for ConcreteAssistantPanelDelegate { fn active_context_editor( &self, workspace: &mut Workspace, - cx: &mut ViewContext, - ) -> Option> { + _window: &mut Window, + cx: &mut Context, + ) -> Option> { let panel = workspace.panel::(cx)?; panel.read(cx).active_context_editor(cx) } @@ -1308,51 +1378,56 @@ impl AssistantPanelDelegate for ConcreteAssistantPanelDelegate { &self, workspace: &mut Workspace, path: PathBuf, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { let Some(panel) = workspace.panel::(cx) else { return Task::ready(Err(anyhow!("no Assistant panel found"))); }; - panel.update(cx, |panel, cx| panel.open_saved_context(path, cx)) + panel.update(cx, |panel, cx| panel.open_saved_context(path, window, cx)) } fn open_remote_context( &self, workspace: &mut Workspace, context_id: ContextId, - cx: &mut ViewContext, - ) -> Task>> { + window: &mut Window, + cx: &mut Context, + ) -> Task>> { let Some(panel) = workspace.panel::(cx) else { return Task::ready(Err(anyhow!("no Assistant panel found"))); }; - panel.update(cx, |panel, cx| panel.open_remote_context(context_id, cx)) + panel.update(cx, |panel, cx| { + panel.open_remote_context(context_id, window, cx) + }) } fn quote_selection( &self, workspace: &mut Workspace, creases: Vec<(String, String)>, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let Some(panel) = workspace.panel::(cx) else { return; }; - if !panel.focus_handle(cx).contains_focused(cx) { - workspace.toggle_panel_focus::(cx); + if !panel.focus_handle(cx).contains_focused(window, cx) { + workspace.toggle_panel_focus::(window, cx); } panel.update(cx, |_, cx| { // Wait to create a new context until the workspace is no longer // being updated. - cx.defer(move |panel, cx| { + cx.defer_in(window, move |panel, window, cx| { if let Some(context) = panel .active_context_editor(cx) - .or_else(|| panel.new_context(cx)) + .or_else(|| panel.new_context(window, cx)) { - context.update(cx, |context, cx| context.quote_creases(creases, cx)); + context.update(cx, |context, cx| context.quote_creases(creases, window, cx)); }; }); }); diff --git a/crates/assistant/src/inline_assistant.rs b/crates/assistant/src/inline_assistant.rs index 3e6d837e40..94dd220f17 100644 --- a/crates/assistant/src/inline_assistant.rs +++ b/crates/assistant/src/inline_assistant.rs @@ -26,9 +26,9 @@ use futures::{ join, SinkExt, Stream, StreamExt, }; use gpui::{ - anchored, deferred, point, AnyElement, AppContext, ClickEvent, CursorStyle, EventEmitter, - FocusHandle, FocusableView, FontWeight, Global, HighlightStyle, Model, ModelContext, - Subscription, Task, TextStyle, UpdateGlobal, View, ViewContext, WeakView, WindowContext, + anchored, deferred, point, AnyElement, App, ClickEvent, Context, CursorStyle, Entity, + EventEmitter, FocusHandle, Focusable, FontWeight, Global, HighlightStyle, Subscription, Task, + TextStyle, UpdateGlobal, WeakEntity, Window, }; use language::{Buffer, IndentKind, Point, Selection, TransactionId}; use language_model::{ @@ -70,17 +70,20 @@ pub fn init( fs: Arc, prompt_builder: Arc, telemetry: Arc, - cx: &mut AppContext, + cx: &mut App, ) { cx.set_global(InlineAssistant::new(fs, prompt_builder, telemetry)); - cx.observe_new_views(|_, cx| { - let workspace = cx.view().clone(); + cx.observe_new(|_, window, cx| { + let Some(window) = window else { + return; + }; + let workspace = cx.model().clone(); InlineAssistant::update_global(cx, |inline_assistant, cx| { - inline_assistant.register_workspace(&workspace, cx) + inline_assistant.register_workspace(&workspace, window, cx) }); - cx.observe_flag::({ - |is_assistant2_enabled, _view, cx| { + cx.observe_flag::(window, { + |is_assistant2_enabled, _workspace, _window, cx| { InlineAssistant::update_global(cx, |inline_assistant, _cx| { inline_assistant.is_assistant2_enabled = is_assistant2_enabled; }); @@ -97,9 +100,9 @@ pub struct InlineAssistant { next_assist_id: InlineAssistId, next_assist_group_id: InlineAssistGroupId, assists: HashMap, - assists_by_editor: HashMap, EditorInlineAssists>, + assists_by_editor: HashMap, EditorInlineAssists>, assist_groups: HashMap, - confirmed_assists: HashMap>, + confirmed_assists: HashMap>, prompt_history: VecDeque, prompt_builder: Arc, telemetry: Arc, @@ -130,13 +133,19 @@ impl InlineAssistant { } } - pub fn register_workspace(&mut self, workspace: &View, cx: &mut WindowContext) { - cx.subscribe(workspace, |workspace, event, cx| { - Self::update_global(cx, |this, cx| { - this.handle_workspace_event(workspace, event, cx) - }); - }) - .detach(); + pub fn register_workspace( + &mut self, + workspace: &Entity, + window: &mut Window, + cx: &mut App, + ) { + window + .subscribe(workspace, cx, |workspace, event, window, cx| { + Self::update_global(cx, |this, cx| { + this.handle_workspace_event(workspace, event, window, cx) + }); + }) + .detach(); let workspace = workspace.downgrade(); cx.observe_global::(move |cx| { @@ -156,9 +165,10 @@ impl InlineAssistant { fn handle_workspace_event( &mut self, - workspace: View, + workspace: Entity, event: &workspace::Event, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { match event { workspace::Event::UserSavedItem { item, .. } => { @@ -168,14 +178,14 @@ impl InlineAssistant { for assist_id in editor_assists.assist_ids.clone() { let assist = &self.assists[&assist_id]; if let CodegenStatus::Done = assist.codegen.read(cx).status(cx) { - self.finish_assist(assist_id, false, cx) + self.finish_assist(assist_id, false, window, cx) } } } } } workspace::Event::ItemAdded { item } => { - self.register_workspace_item(&workspace, item.as_ref(), cx); + self.register_workspace_item(&workspace, item.as_ref(), window, cx); } _ => (), } @@ -183,23 +193,28 @@ impl InlineAssistant { fn register_workspace_item( &mut self, - workspace: &View, + workspace: &Entity, item: &dyn ItemHandle, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { let is_assistant2_enabled = self.is_assistant2_enabled; if let Some(editor) = item.act_as::(cx) { editor.update(cx, |editor, cx| { if is_assistant2_enabled { - editor - .remove_code_action_provider(ASSISTANT_CODE_ACTION_PROVIDER_ID.into(), cx); + editor.remove_code_action_provider( + ASSISTANT_CODE_ACTION_PROVIDER_ID.into(), + window, + cx, + ); } else { editor.add_code_action_provider( Rc::new(AssistantCodeActionProvider { - editor: cx.view().downgrade(), + editor: cx.model().downgrade(), workspace: workspace.downgrade(), }), + window, cx, ); } @@ -209,11 +224,12 @@ impl InlineAssistant { pub fn assist( &mut self, - editor: &View, - workspace: Option>, - assistant_panel: Option<&View>, + editor: &Entity, + workspace: Option>, + assistant_panel: Option<&Entity>, initial_prompt: Option, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { let (snapshot, initial_selections) = editor.update(cx, |editor, cx| { ( @@ -280,15 +296,14 @@ impl InlineAssistant { } let assist_group_id = self.next_assist_group_id.post_inc(); - let prompt_buffer = - cx.new_model(|cx| Buffer::local(initial_prompt.unwrap_or_default(), cx)); - let prompt_buffer = cx.new_model(|cx| MultiBuffer::singleton(prompt_buffer, cx)); + let prompt_buffer = cx.new(|cx| Buffer::local(initial_prompt.unwrap_or_default(), cx)); + let prompt_buffer = cx.new(|cx| MultiBuffer::singleton(prompt_buffer, cx)); let mut assists = Vec::new(); let mut assist_to_focus = None; for range in codegen_ranges { let assist_id = self.next_assist_id.post_inc(); - let codegen = cx.new_model(|cx| { + let codegen = cx.new(|cx| { Codegen::new( editor.read(cx).buffer().clone(), range.clone(), @@ -300,7 +315,7 @@ impl InlineAssistant { }); let gutter_dimensions = Arc::new(Mutex::new(GutterDimensions::default())); - let prompt_editor = cx.new_view(|cx| { + let prompt_editor = cx.new(|cx| { PromptEditor::new( assist_id, gutter_dimensions.clone(), @@ -311,6 +326,7 @@ impl InlineAssistant { assistant_panel, workspace.clone(), self.fs.clone(), + window, cx, ) }); @@ -341,7 +357,7 @@ impl InlineAssistant { let editor_assists = self .assists_by_editor .entry(editor.downgrade()) - .or_insert_with(|| EditorInlineAssists::new(&editor, cx)); + .or_insert_with(|| EditorInlineAssists::new(&editor, window, cx)); let mut assist_group = InlineAssistGroup::new(); for (assist_id, range, prompt_editor, prompt_block_id, end_block_id) in assists { self.assists.insert( @@ -357,6 +373,7 @@ impl InlineAssistant { range, prompt_editor.read(cx).codegen.clone(), workspace.clone(), + window, cx, ), ); @@ -366,25 +383,26 @@ impl InlineAssistant { self.assist_groups.insert(assist_group_id, assist_group); if let Some(assist_id) = assist_to_focus { - self.focus_assist(assist_id, cx); + self.focus_assist(assist_id, window, cx); } } #[allow(clippy::too_many_arguments)] pub fn suggest_assist( &mut self, - editor: &View, + editor: &Entity, mut range: Range, initial_prompt: String, initial_transaction_id: Option, focus: bool, - workspace: Option>, - assistant_panel: Option<&View>, - cx: &mut WindowContext, + workspace: Option>, + assistant_panel: Option<&Entity>, + window: &mut Window, + cx: &mut App, ) -> InlineAssistId { let assist_group_id = self.next_assist_group_id.post_inc(); - let prompt_buffer = cx.new_model(|cx| Buffer::local(&initial_prompt, cx)); - let prompt_buffer = cx.new_model(|cx| MultiBuffer::singleton(prompt_buffer, cx)); + let prompt_buffer = cx.new(|cx| Buffer::local(&initial_prompt, cx)); + let prompt_buffer = cx.new(|cx| MultiBuffer::singleton(prompt_buffer, cx)); let assist_id = self.next_assist_id.post_inc(); @@ -395,7 +413,7 @@ impl InlineAssistant { range.end = range.end.bias_right(&snapshot); } - let codegen = cx.new_model(|cx| { + let codegen = cx.new(|cx| { Codegen::new( editor.read(cx).buffer().clone(), range.clone(), @@ -407,7 +425,7 @@ impl InlineAssistant { }); let gutter_dimensions = Arc::new(Mutex::new(GutterDimensions::default())); - let prompt_editor = cx.new_view(|cx| { + let prompt_editor = cx.new(|cx| { PromptEditor::new( assist_id, gutter_dimensions.clone(), @@ -418,6 +436,7 @@ impl InlineAssistant { assistant_panel, workspace.clone(), self.fs.clone(), + window, cx, ) }); @@ -428,7 +447,7 @@ impl InlineAssistant { let editor_assists = self .assists_by_editor .entry(editor.downgrade()) - .or_insert_with(|| EditorInlineAssists::new(&editor, cx)); + .or_insert_with(|| EditorInlineAssists::new(&editor, window, cx)); let mut assist_group = InlineAssistGroup::new(); self.assists.insert( @@ -444,6 +463,7 @@ impl InlineAssistant { range, prompt_editor.read(cx).codegen.clone(), workspace.clone(), + window, cx, ), ); @@ -452,7 +472,7 @@ impl InlineAssistant { self.assist_groups.insert(assist_group_id, assist_group); if focus { - self.focus_assist(assist_id, cx); + self.focus_assist(assist_id, window, cx); } assist_id @@ -460,10 +480,10 @@ impl InlineAssistant { fn insert_assist_blocks( &self, - editor: &View, + editor: &Entity, range: &Range, - prompt_editor: &View, - cx: &mut WindowContext, + prompt_editor: &Entity, + cx: &mut App, ) -> [CustomBlockId; 2] { let prompt_editor_height = prompt_editor.update(cx, |prompt_editor, cx| { prompt_editor @@ -500,7 +520,7 @@ impl InlineAssistant { }) } - fn handle_prompt_editor_focus_in(&mut self, assist_id: InlineAssistId, cx: &mut WindowContext) { + fn handle_prompt_editor_focus_in(&mut self, assist_id: InlineAssistId, cx: &mut App) { let assist = &self.assists[&assist_id]; let Some(decorations) = assist.decorations.as_ref() else { return; @@ -541,11 +561,7 @@ impl InlineAssistant { .ok(); } - fn handle_prompt_editor_focus_out( - &mut self, - assist_id: InlineAssistId, - cx: &mut WindowContext, - ) { + fn handle_prompt_editor_focus_out(&mut self, assist_id: InlineAssistId, cx: &mut App) { let assist = &self.assists[&assist_id]; let assist_group = self.assist_groups.get_mut(&assist.group_id).unwrap(); if assist_group.active_assist_id == Some(assist_id) { @@ -564,31 +580,32 @@ impl InlineAssistant { fn handle_prompt_editor_event( &mut self, - prompt_editor: View, + prompt_editor: Entity, event: &PromptEditorEvent, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { let assist_id = prompt_editor.read(cx).id; match event { PromptEditorEvent::StartRequested => { - self.start_assist(assist_id, cx); + self.start_assist(assist_id, window, cx); } PromptEditorEvent::StopRequested => { self.stop_assist(assist_id, cx); } PromptEditorEvent::ConfirmRequested => { - self.finish_assist(assist_id, false, cx); + self.finish_assist(assist_id, false, window, cx); } PromptEditorEvent::CancelRequested => { - self.finish_assist(assist_id, true, cx); + self.finish_assist(assist_id, true, window, cx); } PromptEditorEvent::DismissRequested => { - self.dismiss_assist(assist_id, cx); + self.dismiss_assist(assist_id, window, cx); } } } - fn handle_editor_newline(&mut self, editor: View, cx: &mut WindowContext) { + fn handle_editor_newline(&mut self, editor: Entity, window: &mut Window, cx: &mut App) { let Some(editor_assists) = self.assists_by_editor.get(&editor.downgrade()) else { return; }; @@ -606,9 +623,9 @@ impl InlineAssistant { if assist_range.contains(&selection.start) && assist_range.contains(&selection.end) { if matches!(assist.codegen.read(cx).status(cx), CodegenStatus::Pending) { - self.dismiss_assist(*assist_id, cx); + self.dismiss_assist(*assist_id, window, cx); } else { - self.finish_assist(*assist_id, false, cx); + self.finish_assist(*assist_id, false, window, cx); } return; @@ -619,7 +636,7 @@ impl InlineAssistant { cx.propagate(); } - fn handle_editor_cancel(&mut self, editor: View, cx: &mut WindowContext) { + fn handle_editor_cancel(&mut self, editor: Entity, window: &mut Window, cx: &mut App) { let Some(editor_assists) = self.assists_by_editor.get(&editor.downgrade()) else { return; }; @@ -639,7 +656,7 @@ impl InlineAssistant { if assist_range.contains(&selection.start) && assist_range.contains(&selection.end) { - self.focus_assist(*assist_id, cx); + self.focus_assist(*assist_id, window, cx); return; } else { let distance_from_selection = assist_range @@ -666,22 +683,27 @@ impl InlineAssistant { } if let Some((&assist_id, _)) = closest_assist_fallback { - self.focus_assist(assist_id, cx); + self.focus_assist(assist_id, window, cx); } } cx.propagate(); } - fn handle_editor_release(&mut self, editor: WeakView, cx: &mut WindowContext) { + fn handle_editor_release( + &mut self, + editor: WeakEntity, + window: &mut Window, + cx: &mut App, + ) { if let Some(editor_assists) = self.assists_by_editor.get_mut(&editor) { for assist_id in editor_assists.assist_ids.clone() { - self.finish_assist(assist_id, true, cx); + self.finish_assist(assist_id, true, window, cx); } } } - fn handle_editor_change(&mut self, editor: View, cx: &mut WindowContext) { + fn handle_editor_change(&mut self, editor: Entity, window: &mut Window, cx: &mut App) { let Some(editor_assists) = self.assists_by_editor.get(&editor.downgrade()) else { return; }; @@ -701,16 +723,17 @@ impl InlineAssistant { .0 as f32 - scroll_lock.distance_from_top; if target_scroll_top != scroll_position.y { - editor.set_scroll_position(point(scroll_position.x, target_scroll_top), cx); + editor.set_scroll_position(point(scroll_position.x, target_scroll_top), window, cx); } }); } fn handle_editor_event( &mut self, - editor: View, + editor: Entity, event: &EditorEvent, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { let Some(editor_assists) = self.assists_by_editor.get_mut(&editor.downgrade()) else { return; @@ -734,7 +757,7 @@ impl InlineAssistant { .iter() .any(|range| range.overlaps(&assist_range)) { - self.finish_assist(assist_id, false, cx); + self.finish_assist(assist_id, false, window, cx); } } } @@ -762,7 +785,11 @@ impl InlineAssistant { for assist_id in editor_assists.assist_ids.clone() { let assist = &self.assists[&assist_id]; if let Some(decorations) = assist.decorations.as_ref() { - if decorations.prompt_editor.focus_handle(cx).is_focused(cx) { + if decorations + .prompt_editor + .focus_handle(cx) + .is_focused(window) + { return; } } @@ -774,18 +801,24 @@ impl InlineAssistant { } } - pub fn finish_assist(&mut self, assist_id: InlineAssistId, undo: bool, cx: &mut WindowContext) { + pub fn finish_assist( + &mut self, + assist_id: InlineAssistId, + undo: bool, + window: &mut Window, + cx: &mut App, + ) { if let Some(assist) = self.assists.get(&assist_id) { let assist_group_id = assist.group_id; if self.assist_groups[&assist_group_id].linked { - for assist_id in self.unlink_assist_group(assist_group_id, cx) { - self.finish_assist(assist_id, undo, cx); + for assist_id in self.unlink_assist_group(assist_group_id, window, cx) { + self.finish_assist(assist_id, undo, window, cx); } return; } } - self.dismiss_assist(assist_id, cx); + self.dismiss_assist(assist_id, window, cx); if let Some(assist) = self.assists.remove(&assist_id) { if let hash_map::Entry::Occupied(mut entry) = self.assist_groups.entry(assist.group_id) @@ -854,7 +887,12 @@ impl InlineAssistant { } } - fn dismiss_assist(&mut self, assist_id: InlineAssistId, cx: &mut WindowContext) -> bool { + fn dismiss_assist( + &mut self, + assist_id: InlineAssistId, + window: &mut Window, + cx: &mut App, + ) -> bool { let Some(assist) = self.assists.get_mut(&assist_id) else { return false; }; @@ -875,9 +913,9 @@ impl InlineAssistant { if decorations .prompt_editor .focus_handle(cx) - .contains_focused(cx) + .contains_focused(window, cx) { - self.focus_next_assist(assist_id, cx); + self.focus_next_assist(assist_id, window, cx); } if let Some(editor_assists) = self.assists_by_editor.get_mut(&editor.downgrade()) { @@ -894,7 +932,7 @@ impl InlineAssistant { true } - fn focus_next_assist(&mut self, assist_id: InlineAssistId, cx: &mut WindowContext) { + fn focus_next_assist(&mut self, assist_id: InlineAssistId, window: &mut Window, cx: &mut App) { let Some(assist) = self.assists.get(&assist_id) else { return; }; @@ -914,15 +952,18 @@ impl InlineAssistant { for assist_id in assist_ids { let assist = &self.assists[assist_id]; if assist.decorations.is_some() { - self.focus_assist(*assist_id, cx); + self.focus_assist(*assist_id, window, cx); return; } } - assist.editor.update(cx, |editor, cx| editor.focus(cx)).ok(); + assist + .editor + .update(cx, |editor, cx| window.focus(&editor.focus_handle(cx))) + .ok(); } - fn focus_assist(&mut self, assist_id: InlineAssistId, cx: &mut WindowContext) { + fn focus_assist(&mut self, assist_id: InlineAssistId, window: &mut Window, cx: &mut App) { let Some(assist) = self.assists.get(&assist_id) else { return; }; @@ -930,16 +971,21 @@ impl InlineAssistant { if let Some(decorations) = assist.decorations.as_ref() { decorations.prompt_editor.update(cx, |prompt_editor, cx| { prompt_editor.editor.update(cx, |editor, cx| { - editor.focus(cx); - editor.select_all(&SelectAll, cx); + window.focus(&editor.focus_handle(cx)); + editor.select_all(&SelectAll, window, cx); }) }); } - self.scroll_to_assist(assist_id, cx); + self.scroll_to_assist(assist_id, window, cx); } - pub fn scroll_to_assist(&mut self, assist_id: InlineAssistId, cx: &mut WindowContext) { + pub fn scroll_to_assist( + &mut self, + assist_id: InlineAssistId, + window: &mut Window, + cx: &mut App, + ) { let Some(assist) = self.assists.get(&assist_id) else { return; }; @@ -949,7 +995,7 @@ impl InlineAssistant { let position = assist.range.start; editor.update(cx, |editor, cx| { - editor.change_selections(None, cx, |selections| { + editor.change_selections(None, window, cx, |selections| { selections.select_anchor_ranges([position..position]) }); @@ -965,7 +1011,7 @@ impl InlineAssistant { .unwrap() .0 as f32; } else { - let snapshot = editor.snapshot(cx); + let snapshot = editor.snapshot(window, cx); let start_row = assist .range .start @@ -982,13 +1028,16 @@ impl InlineAssistant { let scroll_bottom = scroll_top + height_in_lines; if scroll_target_top < scroll_top { - editor.set_scroll_position(point(0., scroll_target_top), cx); + editor.set_scroll_position(point(0., scroll_target_top), window, cx); } else if scroll_target_bottom > scroll_bottom { if (scroll_target_bottom - scroll_target_top) <= height_in_lines { - editor - .set_scroll_position(point(0., scroll_target_bottom - height_in_lines), cx); + editor.set_scroll_position( + point(0., scroll_target_bottom - height_in_lines), + window, + cx, + ); } else { - editor.set_scroll_position(point(0., scroll_target_top), cx); + editor.set_scroll_position(point(0., scroll_target_top), window, cx); } } }); @@ -997,7 +1046,8 @@ impl InlineAssistant { fn unlink_assist_group( &mut self, assist_group_id: InlineAssistGroupId, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Vec { let assist_group = self.assist_groups.get_mut(&assist_group_id).unwrap(); assist_group.linked = false; @@ -1006,13 +1056,13 @@ impl InlineAssistant { if let Some(editor_decorations) = assist.decorations.as_ref() { editor_decorations .prompt_editor - .update(cx, |prompt_editor, cx| prompt_editor.unlink(cx)); + .update(cx, |prompt_editor, cx| prompt_editor.unlink(window, cx)); } } assist_group.assist_ids.clone() } - pub fn start_assist(&mut self, assist_id: InlineAssistId, cx: &mut WindowContext) { + pub fn start_assist(&mut self, assist_id: InlineAssistId, window: &mut Window, cx: &mut App) { let assist = if let Some(assist) = self.assists.get_mut(&assist_id) { assist } else { @@ -1021,8 +1071,8 @@ impl InlineAssistant { let assist_group_id = assist.group_id; if self.assist_groups[&assist_group_id].linked { - for assist_id in self.unlink_assist_group(assist_group_id, cx) { - self.start_assist(assist_id, cx); + for assist_id in self.unlink_assist_group(assist_group_id, window, cx) { + self.start_assist(assist_id, window, cx); } return; } @@ -1047,7 +1097,7 @@ impl InlineAssistant { .log_err(); } - pub fn stop_assist(&mut self, assist_id: InlineAssistId, cx: &mut WindowContext) { + pub fn stop_assist(&mut self, assist_id: InlineAssistId, cx: &mut App) { let assist = if let Some(assist) = self.assists.get_mut(&assist_id) { assist } else { @@ -1057,7 +1107,7 @@ impl InlineAssistant { assist.codegen.update(cx, |codegen, cx| codegen.stop(cx)); } - fn update_editor_highlights(&self, editor: &View, cx: &mut WindowContext) { + fn update_editor_highlights(&self, editor: &Entity, cx: &mut App) { let mut gutter_pending_ranges = Vec::new(); let mut gutter_transformed_ranges = Vec::new(); let mut foreground_ranges = Vec::new(); @@ -1150,9 +1200,10 @@ impl InlineAssistant { fn update_editor_blocks( &mut self, - editor: &View, + editor: &Entity, assist_id: InlineAssistId, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { let Some(assist) = self.assists.get_mut(&assist_id) else { return; @@ -1182,10 +1233,9 @@ impl InlineAssistant { )) .unwrap(); - let deleted_lines_editor = cx.new_view(|cx| { - let multi_buffer = cx.new_model(|_| { - MultiBuffer::without_headers(language::Capability::ReadOnly) - }); + let deleted_lines_editor = cx.new(|cx| { + let multi_buffer = + cx.new(|_| MultiBuffer::without_headers(language::Capability::ReadOnly)); multi_buffer.update(cx, |multi_buffer, cx| { multi_buffer.push_excerpts( old_buffer.clone(), @@ -1198,14 +1248,14 @@ impl InlineAssistant { }); enum DeletedLines {} - let mut editor = Editor::for_multibuffer(multi_buffer, None, true, cx); + let mut editor = Editor::for_multibuffer(multi_buffer, None, true, window, cx); editor.set_soft_wrap_mode(language::language_settings::SoftWrap::None, cx); editor.set_show_wrap_guides(false, cx); editor.set_show_gutter(false, cx); editor.scroll_manager.set_forbid_vertical_scroll(true); editor.set_show_scrollbars(false, cx); editor.set_read_only(true); - editor.set_show_inline_completions(Some(false), cx); + editor.set_show_inline_completions(Some(false), window, cx); editor.highlight_rows::( Anchor::min()..Anchor::max(), cx.theme().status().deleted_background, @@ -1226,7 +1276,7 @@ impl InlineAssistant { .block_mouse_down() .bg(cx.theme().status().deleted_background) .size_full() - .h(height as f32 * cx.line_height()) + .h(height as f32 * cx.window.line_height()) .pl(cx.gutter_dimensions.full_width()) .child(deleted_lines_editor.clone()) .into_any_element() @@ -1257,14 +1307,13 @@ struct InlineAssistScrollLock { } impl EditorInlineAssists { - #[allow(clippy::too_many_arguments)] - fn new(editor: &View, cx: &mut WindowContext) -> Self { + fn new(editor: &Entity, window: &mut Window, cx: &mut App) -> Self { let (highlight_updates_tx, mut highlight_updates_rx) = async_watch::channel(()); Self { assist_ids: Vec::new(), scroll_lock: None, highlight_updates: highlight_updates_tx, - _update_highlights: cx.spawn(|mut cx| { + _update_highlights: cx.spawn(|cx| { let editor = editor.downgrade(); async move { while let Ok(()) = highlight_updates_rx.changed().await { @@ -1277,47 +1326,43 @@ impl EditorInlineAssists { } }), _subscriptions: vec![ - cx.observe_release(editor, { + cx.observe_release_in(editor, window, { let editor = editor.downgrade(); - |_, cx| { + |_, window, cx| { InlineAssistant::update_global(cx, |this, cx| { - this.handle_editor_release(editor, cx); + this.handle_editor_release(editor, window, cx); }) } }), - cx.observe(editor, move |editor, cx| { + window.observe(editor, cx, move |editor, window, cx| { InlineAssistant::update_global(cx, |this, cx| { - this.handle_editor_change(editor, cx) + this.handle_editor_change(editor, window, cx) }) }), - cx.subscribe(editor, move |editor, event, cx| { + window.subscribe(editor, cx, move |editor, event, window, cx| { InlineAssistant::update_global(cx, |this, cx| { - this.handle_editor_event(editor, event, cx) + this.handle_editor_event(editor, event, window, cx) }) }), editor.update(cx, |editor, cx| { - let editor_handle = cx.view().downgrade(); - editor.register_action( - move |_: &editor::actions::Newline, cx: &mut WindowContext| { - InlineAssistant::update_global(cx, |this, cx| { - if let Some(editor) = editor_handle.upgrade() { - this.handle_editor_newline(editor, cx) - } - }) - }, - ) + let editor_handle = cx.model().downgrade(); + editor.register_action(move |_: &editor::actions::Newline, window, cx| { + InlineAssistant::update_global(cx, |this, cx| { + if let Some(editor) = editor_handle.upgrade() { + this.handle_editor_newline(editor, window, cx) + } + }) + }) }), editor.update(cx, |editor, cx| { - let editor_handle = cx.view().downgrade(); - editor.register_action( - move |_: &editor::actions::Cancel, cx: &mut WindowContext| { - InlineAssistant::update_global(cx, |this, cx| { - if let Some(editor) = editor_handle.upgrade() { - this.handle_editor_cancel(editor, cx) - } - }) - }, - ) + let editor_handle = cx.model().downgrade(); + editor.register_action(move |_: &editor::actions::Cancel, window, cx| { + InlineAssistant::update_global(cx, |this, cx| { + if let Some(editor) = editor_handle.upgrade() { + this.handle_editor_cancel(editor, window, cx) + } + }) + }) }), ], } @@ -1340,7 +1385,7 @@ impl InlineAssistGroup { } } -fn build_assist_editor_renderer(editor: &View) -> RenderBlock { +fn build_assist_editor_renderer(editor: &Entity) -> RenderBlock { let editor = editor.clone(); Arc::new(move |cx: &mut BlockContext| { *editor.read(cx).gutter_dimensions.lock() = *cx.gutter_dimensions; @@ -1380,20 +1425,20 @@ enum PromptEditorEvent { struct PromptEditor { id: InlineAssistId, - editor: View, - language_model_selector: View, + editor: Entity, + language_model_selector: Entity, edited_since_done: bool, gutter_dimensions: Arc>, prompt_history: VecDeque, prompt_history_ix: Option, pending_prompt: String, - codegen: Model, + codegen: Entity, _codegen_subscription: Subscription, editor_subscriptions: Vec, pending_token_count: Task>, token_counts: Option, _token_count_subscriptions: Vec, - workspace: Option>, + workspace: Option>, show_rate_limit_notice: bool, } @@ -1406,7 +1451,7 @@ pub struct TokenCounts { impl EventEmitter for PromptEditor {} impl Render for PromptEditor { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { let gutter_dimensions = *self.gutter_dimensions.lock(); let codegen = self.codegen.read(cx); @@ -1422,17 +1467,21 @@ impl Render for PromptEditor { IconButton::new("cancel", IconName::Close) .icon_color(Color::Muted) .shape(IconButtonShape::Square) - .tooltip(|cx| Tooltip::for_action("Cancel Assist", &menu::Cancel, cx)) + .tooltip(|window, cx| { + Tooltip::for_action("Cancel Assist", &menu::Cancel, window, cx) + }) .on_click( - cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::CancelRequested)), + cx.listener(|_, _, _, cx| cx.emit(PromptEditorEvent::CancelRequested)), ) .into_any_element(), IconButton::new("start", IconName::SparkleAlt) .icon_color(Color::Muted) .shape(IconButtonShape::Square) - .tooltip(|cx| Tooltip::for_action("Transform", &menu::Confirm, cx)) + .tooltip(|window, cx| { + Tooltip::for_action("Transform", &menu::Confirm, window, cx) + }) .on_click( - cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::StartRequested)), + cx.listener(|_, _, _, cx| cx.emit(PromptEditorEvent::StartRequested)), ) .into_any_element(), ] @@ -1442,23 +1491,26 @@ impl Render for PromptEditor { IconButton::new("cancel", IconName::Close) .icon_color(Color::Muted) .shape(IconButtonShape::Square) - .tooltip(|cx| Tooltip::text("Cancel Assist", cx)) + .tooltip(Tooltip::text("Cancel Assist")) .on_click( - cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::CancelRequested)), + cx.listener(|_, _, _, cx| cx.emit(PromptEditorEvent::CancelRequested)), ) .into_any_element(), IconButton::new("stop", IconName::Stop) .icon_color(Color::Error) .shape(IconButtonShape::Square) - .tooltip(|cx| { + .tooltip(|window, cx| { Tooltip::with_meta( "Interrupt Transformation", Some(&menu::Cancel), "Changes won't be discarded", + window, cx, ) }) - .on_click(cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::StopRequested))) + .on_click( + cx.listener(|_, _, _, cx| cx.emit(PromptEditorEvent::StopRequested)), + ) .into_any_element(), ] } @@ -1476,23 +1528,26 @@ impl Render for PromptEditor { IconButton::new("cancel", IconName::Close) .icon_color(Color::Muted) .shape(IconButtonShape::Square) - .tooltip(|cx| Tooltip::for_action("Cancel Assist", &menu::Cancel, cx)) + .tooltip(|window, cx| { + Tooltip::for_action("Cancel Assist", &menu::Cancel, window, cx) + }) .on_click( - cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::CancelRequested)), + cx.listener(|_, _, _, cx| cx.emit(PromptEditorEvent::CancelRequested)), ) .into_any_element(), IconButton::new("restart", IconName::RotateCw) .icon_color(Color::Muted) .shape(IconButtonShape::Square) - .tooltip(|cx| { + .tooltip(|window, cx| { Tooltip::with_meta( "Regenerate Transformation", Some(restart_key), "Current change will be discarded", + window, cx, ) }) - .on_click(cx.listener(|_, _, cx| { + .on_click(cx.listener(|_, _, _, cx| { cx.emit(PromptEditorEvent::StartRequested); })) .into_any_element(), @@ -1500,8 +1555,10 @@ impl Render for PromptEditor { IconButton::new("confirm", IconName::Check) .icon_color(Color::Info) .shape(IconButtonShape::Square) - .tooltip(|cx| Tooltip::for_action("Confirm Assist", &menu::Confirm, cx)) - .on_click(cx.listener(|_, _, cx| { + .tooltip(|window, cx| { + Tooltip::for_action("Confirm Assist", &menu::Confirm, window, cx) + }) + .on_click(cx.listener(|_, _, _, cx| { cx.emit(PromptEditorEvent::ConfirmRequested); })) .into_any_element() @@ -1520,7 +1577,7 @@ impl Render for PromptEditor { .border_y_1() .border_color(cx.theme().status().info_border) .size_full() - .py(cx.line_height() / 2.5) + .py(window.line_height() / 2.5) .on_action(cx.listener(Self::confirm)) .on_action(cx.listener(Self::cancel)) .on_action(cx.listener(Self::restart)) @@ -1539,7 +1596,7 @@ impl Render for PromptEditor { .shape(IconButtonShape::Square) .icon_size(IconSize::Small) .icon_color(Color::Muted) - .tooltip(move |cx| { + .tooltip(move |window, cx| { Tooltip::with_meta( format!( "Using {}", @@ -1550,6 +1607,7 @@ impl Render for PromptEditor { ), None, "Change Model", + window, cx, ) }), @@ -1586,7 +1644,7 @@ impl Render for PromptEditor { el.child( div() .id("error") - .tooltip(move |cx| Tooltip::text(error_message.clone(), cx)) + .tooltip(Tooltip::text(error_message)) .child( Icon::new(IconName::XCircle) .size(IconSize::Small) @@ -1607,8 +1665,8 @@ impl Render for PromptEditor { } } -impl FocusableView for PromptEditor { - fn focus_handle(&self, cx: &AppContext) -> FocusHandle { +impl Focusable for PromptEditor { + fn focus_handle(&self, cx: &App) -> FocusHandle { self.editor.focus_handle(cx) } } @@ -1621,15 +1679,16 @@ impl PromptEditor { id: InlineAssistId, gutter_dimensions: Arc>, prompt_history: VecDeque, - prompt_buffer: Model, - codegen: Model, - parent_editor: &View, - assistant_panel: Option<&View>, - workspace: Option>, + prompt_buffer: Entity, + codegen: Entity, + parent_editor: &Entity, + assistant_panel: Option<&Entity>, + workspace: Option>, fs: Arc, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Self { - let prompt_editor = cx.new_view(|cx| { + let prompt_editor = cx.new(|cx| { let mut editor = Editor::new( EditorMode::AutoHeight { max_lines: Self::MAX_LINES as usize, @@ -1637,6 +1696,7 @@ impl PromptEditor { prompt_buffer, None, false, + window, cx, ); editor.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx); @@ -1644,22 +1704,28 @@ impl PromptEditor { // always show the cursor (even when it isn't focused) because // typing in one will make what you typed appear in all of them. editor.set_show_cursor_when_unfocused(true, cx); - editor.set_placeholder_text(Self::placeholder_text(codegen.read(cx), cx), cx); + editor.set_placeholder_text(Self::placeholder_text(codegen.read(cx), window), cx); editor }); let mut token_count_subscriptions = Vec::new(); - token_count_subscriptions - .push(cx.subscribe(parent_editor, Self::handle_parent_editor_event)); + token_count_subscriptions.push(cx.subscribe_in( + parent_editor, + window, + Self::handle_parent_editor_event, + )); if let Some(assistant_panel) = assistant_panel { - token_count_subscriptions - .push(cx.subscribe(assistant_panel, Self::handle_assistant_panel_event)); + token_count_subscriptions.push(cx.subscribe_in( + assistant_panel, + window, + Self::handle_assistant_panel_event, + )); } let mut this = Self { id, editor: prompt_editor, - language_model_selector: cx.new_view(|cx| { + language_model_selector: cx.new(|cx| { let fs = fs.clone(); LanguageModelSelector::new( move |model, cx| { @@ -1669,6 +1735,7 @@ impl PromptEditor { move |settings, _| settings.set_model(model.clone()), ); }, + window, cx, ) }), @@ -1687,45 +1754,48 @@ impl PromptEditor { show_rate_limit_notice: false, }; this.count_tokens(cx); - this.subscribe_to_editor(cx); + this.subscribe_to_editor(window, cx); this } - fn subscribe_to_editor(&mut self, cx: &mut ViewContext) { + fn subscribe_to_editor(&mut self, window: &mut Window, cx: &mut Context) { self.editor_subscriptions.clear(); - self.editor_subscriptions - .push(cx.subscribe(&self.editor, Self::handle_prompt_editor_events)); + self.editor_subscriptions.push(cx.subscribe_in( + &self.editor, + window, + Self::handle_prompt_editor_events, + )); } fn set_show_cursor_when_unfocused( &mut self, show_cursor_when_unfocused: bool, - cx: &mut ViewContext, + cx: &mut Context, ) { self.editor.update(cx, |editor, cx| { editor.set_show_cursor_when_unfocused(show_cursor_when_unfocused, cx) }); } - fn unlink(&mut self, cx: &mut ViewContext) { + fn unlink(&mut self, window: &mut Window, cx: &mut Context) { let prompt = self.prompt(cx); - let focus = self.editor.focus_handle(cx).contains_focused(cx); - self.editor = cx.new_view(|cx| { - let mut editor = Editor::auto_height(Self::MAX_LINES as usize, cx); + let focus = self.editor.focus_handle(cx).contains_focused(window, cx); + self.editor = cx.new(|cx| { + let mut editor = Editor::auto_height(Self::MAX_LINES as usize, window, cx); editor.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx); - editor.set_placeholder_text(Self::placeholder_text(self.codegen.read(cx), cx), cx); + editor.set_placeholder_text(Self::placeholder_text(self.codegen.read(cx), window), cx); editor.set_placeholder_text("Add a prompt…", cx); - editor.set_text(prompt, cx); + editor.set_text(prompt, window, cx); if focus { - editor.focus(cx); + window.focus(&editor.focus_handle(cx)); } editor }); - self.subscribe_to_editor(cx); + self.subscribe_to_editor(window, cx); } - fn placeholder_text(codegen: &Codegen, cx: &WindowContext) -> String { - let context_keybinding = text_for_action(&zed_actions::assistant::ToggleFocus, cx) + fn placeholder_text(codegen: &Codegen, window: &Window) -> String { + let context_keybinding = text_for_action(&zed_actions::assistant::ToggleFocus, window) .map(|keybinding| format!(" • {keybinding} for context")) .unwrap_or_default(); @@ -1738,23 +1808,29 @@ impl PromptEditor { format!("{action}…{context_keybinding} • ↓↑ for history") } - fn prompt(&self, cx: &AppContext) -> String { + fn prompt(&self, cx: &App) -> String { self.editor.read(cx).text(cx) } - fn toggle_rate_limit_notice(&mut self, _: &ClickEvent, cx: &mut ViewContext) { + fn toggle_rate_limit_notice( + &mut self, + _: &ClickEvent, + window: &mut Window, + cx: &mut Context, + ) { self.show_rate_limit_notice = !self.show_rate_limit_notice; if self.show_rate_limit_notice { - cx.focus_view(&self.editor); + window.focus(&self.editor.focus_handle(cx)); } cx.notify(); } fn handle_parent_editor_event( &mut self, - _: View, + _: &Entity, event: &EditorEvent, - cx: &mut ViewContext, + _: &mut Window, + cx: &mut Context, ) { if let EditorEvent::BufferEdited { .. } = event { self.count_tokens(cx); @@ -1763,15 +1839,16 @@ impl PromptEditor { fn handle_assistant_panel_event( &mut self, - _: View, + _: &Entity, event: &AssistantPanelEvent, - cx: &mut ViewContext, + _: &mut Window, + cx: &mut Context, ) { let AssistantPanelEvent::ContextEdited { .. } = event; self.count_tokens(cx); } - fn count_tokens(&mut self, cx: &mut ViewContext) { + fn count_tokens(&mut self, cx: &mut Context) { let assist_id = self.id; self.pending_token_count = cx.spawn(|this, mut cx| async move { cx.background_executor().timer(Duration::from_secs(1)).await; @@ -1794,15 +1871,16 @@ impl PromptEditor { fn handle_prompt_editor_events( &mut self, - _: View, + _: &Entity, event: &EditorEvent, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { match event { EditorEvent::Edited { .. } => { - if let Some(workspace) = cx.window_handle().downcast::() { + if let Some(workspace) = window.window_handle().downcast::() { workspace - .update(cx, |workspace, cx| { + .update(cx, |workspace, _, cx| { let is_via_ssh = workspace .project() .update(cx, |project, _| project.is_via_ssh()); @@ -1839,7 +1917,7 @@ impl PromptEditor { } } - fn handle_codegen_changed(&mut self, _: Model, cx: &mut ViewContext) { + fn handle_codegen_changed(&mut self, _: Entity, cx: &mut Context) { match self.codegen.read(cx).status(cx) { CodegenStatus::Idle => { self.editor @@ -1870,11 +1948,16 @@ impl PromptEditor { } } - fn restart(&mut self, _: &menu::Restart, cx: &mut ViewContext) { + fn restart(&mut self, _: &menu::Restart, _window: &mut Window, cx: &mut Context) { cx.emit(PromptEditorEvent::StartRequested); } - fn cancel(&mut self, _: &editor::actions::Cancel, cx: &mut ViewContext) { + fn cancel( + &mut self, + _: &editor::actions::Cancel, + _window: &mut Window, + cx: &mut Context, + ) { match self.codegen.read(cx).status(cx) { CodegenStatus::Idle | CodegenStatus::Done | CodegenStatus::Error(_) => { cx.emit(PromptEditorEvent::CancelRequested); @@ -1885,7 +1968,7 @@ impl PromptEditor { } } - fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext) { + fn confirm(&mut self, _: &menu::Confirm, _window: &mut Window, cx: &mut Context) { match self.codegen.read(cx).status(cx) { CodegenStatus::Idle => { cx.emit(PromptEditorEvent::StartRequested); @@ -1906,57 +1989,62 @@ impl PromptEditor { } } - fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext) { + fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context) { if let Some(ix) = self.prompt_history_ix { if ix > 0 { self.prompt_history_ix = Some(ix - 1); let prompt = self.prompt_history[ix - 1].as_str(); self.editor.update(cx, |editor, cx| { - editor.set_text(prompt, cx); - editor.move_to_beginning(&Default::default(), cx); + editor.set_text(prompt, window, cx); + editor.move_to_beginning(&Default::default(), window, cx); }); } } else if !self.prompt_history.is_empty() { self.prompt_history_ix = Some(self.prompt_history.len() - 1); let prompt = self.prompt_history[self.prompt_history.len() - 1].as_str(); self.editor.update(cx, |editor, cx| { - editor.set_text(prompt, cx); - editor.move_to_beginning(&Default::default(), cx); + editor.set_text(prompt, window, cx); + editor.move_to_beginning(&Default::default(), window, cx); }); } } - fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext) { + fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context) { if let Some(ix) = self.prompt_history_ix { if ix < self.prompt_history.len() - 1 { self.prompt_history_ix = Some(ix + 1); let prompt = self.prompt_history[ix + 1].as_str(); self.editor.update(cx, |editor, cx| { - editor.set_text(prompt, cx); - editor.move_to_end(&Default::default(), cx) + editor.set_text(prompt, window, cx); + editor.move_to_end(&Default::default(), window, cx) }); } else { self.prompt_history_ix = None; let prompt = self.pending_prompt.as_str(); self.editor.update(cx, |editor, cx| { - editor.set_text(prompt, cx); - editor.move_to_end(&Default::default(), cx) + editor.set_text(prompt, window, cx); + editor.move_to_end(&Default::default(), window, cx) }); } } } - fn cycle_prev(&mut self, _: &CyclePreviousInlineAssist, cx: &mut ViewContext) { + fn cycle_prev( + &mut self, + _: &CyclePreviousInlineAssist, + _: &mut Window, + cx: &mut Context, + ) { self.codegen .update(cx, |codegen, cx| codegen.cycle_prev(cx)); } - fn cycle_next(&mut self, _: &CycleNextInlineAssist, cx: &mut ViewContext) { + fn cycle_next(&mut self, _: &CycleNextInlineAssist, _: &mut Window, cx: &mut Context) { self.codegen .update(cx, |codegen, cx| codegen.cycle_next(cx)); } - fn render_cycle_controls(&self, cx: &ViewContext) -> AnyElement { + fn render_cycle_controls(&self, cx: &Context) -> AnyElement { let codegen = self.codegen.read(cx); let disabled = matches!(codegen.status(cx), CodegenStatus::Idle); @@ -1997,13 +2085,13 @@ impl PromptEditor { .shape(IconButtonShape::Square) .tooltip({ let focus_handle = self.editor.focus_handle(cx); - move |cx| { - cx.new_view(|cx| { + move |window, cx| { + cx.new(|_| { let mut tooltip = Tooltip::new("Previous Alternative").key_binding( KeyBinding::for_action_in( &CyclePreviousInlineAssist, &focus_handle, - cx, + window, ), ); if !disabled && current_index != 0 { @@ -2014,7 +2102,7 @@ impl PromptEditor { .into() } }) - .on_click(cx.listener(|this, _, cx| { + .on_click(cx.listener(|this, _, _, cx| { this.codegen .update(cx, |codegen, cx| codegen.cycle_prev(cx)) })), @@ -2039,13 +2127,13 @@ impl PromptEditor { .shape(IconButtonShape::Square) .tooltip({ let focus_handle = self.editor.focus_handle(cx); - move |cx| { - cx.new_view(|cx| { + move |window, cx| { + cx.new(|_| { let mut tooltip = Tooltip::new("Next Alternative").key_binding( KeyBinding::for_action_in( &CycleNextInlineAssist, &focus_handle, - cx, + window, ), ); if !disabled && current_index != total_models - 1 { @@ -2056,7 +2144,7 @@ impl PromptEditor { .into() } }) - .on_click(cx.listener(|this, _, cx| { + .on_click(cx.listener(|this, _, _, cx| { this.codegen .update(cx, |codegen, cx| codegen.cycle_next(cx)) })), @@ -2064,7 +2152,7 @@ impl PromptEditor { .into_any_element() } - fn render_token_count(&self, cx: &mut ViewContext) -> Option { + fn render_token_count(&self, cx: &mut Context) -> Option { let model = LanguageModelRegistry::read_global(cx).active_model()?; let token_counts = self.token_counts?; let max_token_count = model.max_token_count(); @@ -2094,7 +2182,7 @@ impl PromptEditor { ); if let Some(workspace) = self.workspace.clone() { token_count = token_count - .tooltip(move |cx| { + .tooltip(move |window, cx| { Tooltip::with_meta( format!( "Tokens Used ({} from the Assistant Panel)", @@ -2102,29 +2190,30 @@ impl PromptEditor { ), None, "Click to open the Assistant Panel", + window, cx, ) }) .cursor_pointer() - .on_mouse_down(gpui::MouseButton::Left, |_, cx| cx.stop_propagation()) - .on_click(move |_, cx| { + .on_mouse_down(gpui::MouseButton::Left, |_, _, cx| cx.stop_propagation()) + .on_click(move |_, window, cx| { cx.stop_propagation(); workspace .update(cx, |workspace, cx| { - workspace.focus_panel::(cx) + workspace.focus_panel::(window, cx) }) .ok(); }); } else { token_count = token_count .cursor_default() - .tooltip(|cx| Tooltip::text("Tokens used", cx)); + .tooltip(Tooltip::text("Tokens used")); } Some(token_count) } - fn render_prompt_editor(&self, cx: &mut ViewContext) -> impl IntoElement { + fn render_prompt_editor(&self, cx: &mut Context) -> impl IntoElement { let settings = ThemeSettings::get_global(cx); let text_style = TextStyle { color: if self.editor.read(cx).read_only(cx) { @@ -2150,7 +2239,7 @@ impl PromptEditor { ) } - fn render_rate_limit_notice(&self, cx: &mut ViewContext) -> impl IntoElement { + fn render_rate_limit_notice(&self, cx: &mut Context) -> impl IntoElement { Popover::new().child( v_flex() .occlude() @@ -2174,7 +2263,7 @@ impl PromptEditor { } else { ui::ToggleState::Unselected }, - |selection, cx| { + |selection, _, cx| { let is_dismissed = match selection { ui::ToggleState::Unselected => false, ui::ToggleState::Indeterminate => return, @@ -2193,10 +2282,11 @@ impl PromptEditor { .on_click(cx.listener(Self::toggle_rate_limit_notice)), ) .child(Button::new("more-info", "More Info").on_click( - |_event, cx| { - cx.dispatch_action(Box::new( - zed_actions::OpenAccountSettings, - )) + |_event, window, cx| { + window.dispatch_action( + Box::new(zed_actions::OpenAccountSettings), + cx, + ) }, )), ), @@ -2214,7 +2304,7 @@ fn dismissed_rate_limit_notice() -> bool { .map_or(false, |s| s.is_some()) } -fn set_rate_limit_notice_dismissed(is_dismissed: bool, cx: &mut AppContext) { +fn set_rate_limit_notice_dismissed(is_dismissed: bool, cx: &mut App) { db::write_and_log(cx, move || async move { if is_dismissed { db::kvp::KEY_VALUE_STORE @@ -2231,11 +2321,11 @@ fn set_rate_limit_notice_dismissed(is_dismissed: bool, cx: &mut AppContext) { struct InlineAssist { group_id: InlineAssistGroupId, range: Range, - editor: WeakView, + editor: WeakEntity, decorations: Option, - codegen: Model, + codegen: Entity, _subscriptions: Vec, - workspace: Option>, + workspace: Option>, include_context: bool, } @@ -2245,14 +2335,15 @@ impl InlineAssist { assist_id: InlineAssistId, group_id: InlineAssistGroupId, include_context: bool, - editor: &View, - prompt_editor: &View, + editor: &Entity, + prompt_editor: &Entity, prompt_block_id: CustomBlockId, end_block_id: CustomBlockId, range: Range, - codegen: Model, - workspace: Option>, - cx: &mut WindowContext, + codegen: Entity, + workspace: Option>, + window: &mut Window, + cx: &mut App, ) -> Self { let prompt_editor_focus_handle = prompt_editor.focus_handle(cx); InlineAssist { @@ -2269,24 +2360,28 @@ impl InlineAssist { codegen: codegen.clone(), workspace: workspace.clone(), _subscriptions: vec![ - cx.on_focus_in(&prompt_editor_focus_handle, move |cx| { + window.on_focus_in(&prompt_editor_focus_handle, cx, move |_, cx| { InlineAssistant::update_global(cx, |this, cx| { this.handle_prompt_editor_focus_in(assist_id, cx) }) }), - cx.on_focus_out(&prompt_editor_focus_handle, move |_, cx| { + window.on_focus_out(&prompt_editor_focus_handle, cx, move |_, _, cx| { InlineAssistant::update_global(cx, |this, cx| { this.handle_prompt_editor_focus_out(assist_id, cx) }) }), - cx.subscribe(prompt_editor, |prompt_editor, event, cx| { - InlineAssistant::update_global(cx, |this, cx| { - this.handle_prompt_editor_event(prompt_editor, event, cx) - }) - }), - cx.observe(&codegen, { + window.subscribe( + prompt_editor, + cx, + move |prompt_editor, event, window, cx| { + InlineAssistant::update_global(cx, |this, cx| { + this.handle_prompt_editor_event(prompt_editor, event, window, cx) + }) + }, + ), + window.observe(&codegen, cx, { let editor = editor.downgrade(); - move |_, cx| { + move |_, window, cx| { if let Some(editor) = editor.upgrade() { InlineAssistant::update_global(cx, |this, cx| { if let Some(editor_assists) = @@ -2295,14 +2390,14 @@ impl InlineAssist { editor_assists.highlight_updates.send(()).ok(); } - this.update_editor_blocks(&editor, assist_id, cx); + this.update_editor_blocks(&editor, assist_id, window, cx); }) } } }), - cx.subscribe(&codegen, move |codegen, event, cx| { + window.subscribe(&codegen, cx, move |codegen, event, window, cx| { InlineAssistant::update_global(cx, |this, cx| match event { - CodegenEvent::Undone => this.finish_assist(assist_id, false, cx), + CodegenEvent::Undone => this.finish_assist(assist_id, false, window, cx), CodegenEvent::Finished => { let assist = if let Some(assist) = this.assists.get(&assist_id) { assist @@ -2333,7 +2428,7 @@ impl InlineAssist { } if assist.decorations.is_none() { - this.finish_assist(assist_id, false, cx); + this.finish_assist(assist_id, false, window, cx); } } }) @@ -2342,12 +2437,12 @@ impl InlineAssist { } } - fn user_prompt(&self, cx: &AppContext) -> Option { + fn user_prompt(&self, cx: &App) -> Option { let decorations = self.decorations.as_ref()?; Some(decorations.prompt_editor.read(cx).prompt(cx)) } - fn assistant_panel_context(&self, cx: &WindowContext) -> Option { + fn assistant_panel_context(&self, cx: &mut App) -> Option { if self.include_context { let workspace = self.workspace.as_ref()?; let workspace = workspace.upgrade()?.read(cx); @@ -2364,7 +2459,7 @@ impl InlineAssist { } } - pub fn count_tokens(&self, cx: &WindowContext) -> BoxFuture<'static, Result> { + pub fn count_tokens(&self, cx: &mut App) -> BoxFuture<'static, Result> { let Some(user_prompt) = self.user_prompt(cx) else { return future::ready(Err(anyhow!("no user prompt"))).boxed(); }; @@ -2377,7 +2472,7 @@ impl InlineAssist { struct InlineAssistDecorations { prompt_block_id: CustomBlockId, - prompt_editor: View, + prompt_editor: Entity, removed_line_block_ids: HashSet, end_block_id: CustomBlockId, } @@ -2389,11 +2484,11 @@ pub enum CodegenEvent { } pub struct Codegen { - alternatives: Vec>, + alternatives: Vec>, active_alternative: usize, seen_alternatives: HashSet, subscriptions: Vec, - buffer: Model, + buffer: Entity, range: Range, initial_transaction_id: Option, telemetry: Arc, @@ -2403,14 +2498,14 @@ pub struct Codegen { impl Codegen { pub fn new( - buffer: Model, + buffer: Entity, range: Range, initial_transaction_id: Option, telemetry: Arc, builder: Arc, - cx: &mut ModelContext, + cx: &mut Context, ) -> Self { - let codegen = cx.new_model(|cx| { + let codegen = cx.new(|cx| { CodegenAlternative::new( buffer.clone(), range.clone(), @@ -2436,7 +2531,7 @@ impl Codegen { this } - fn subscribe_to_alternative(&mut self, cx: &mut ModelContext) { + fn subscribe_to_alternative(&mut self, cx: &mut Context) { let codegen = self.active_alternative().clone(); self.subscriptions.clear(); self.subscriptions @@ -2445,22 +2540,22 @@ impl Codegen { .push(cx.subscribe(&codegen, |_, _, event, cx| cx.emit(*event))); } - fn active_alternative(&self) -> &Model { + fn active_alternative(&self) -> &Entity { &self.alternatives[self.active_alternative] } - fn status<'a>(&self, cx: &'a AppContext) -> &'a CodegenStatus { + fn status<'a>(&self, cx: &'a App) -> &'a CodegenStatus { &self.active_alternative().read(cx).status } - fn alternative_count(&self, cx: &AppContext) -> usize { + fn alternative_count(&self, cx: &App) -> usize { LanguageModelRegistry::read_global(cx) .inline_alternative_models() .len() + 1 } - pub fn cycle_prev(&mut self, cx: &mut ModelContext) { + pub fn cycle_prev(&mut self, cx: &mut Context) { let next_active_ix = if self.active_alternative == 0 { self.alternatives.len() - 1 } else { @@ -2469,12 +2564,12 @@ impl Codegen { self.activate(next_active_ix, cx); } - pub fn cycle_next(&mut self, cx: &mut ModelContext) { + pub fn cycle_next(&mut self, cx: &mut Context) { let next_active_ix = (self.active_alternative + 1) % self.alternatives.len(); self.activate(next_active_ix, cx); } - fn activate(&mut self, index: usize, cx: &mut ModelContext) { + fn activate(&mut self, index: usize, cx: &mut Context) { self.active_alternative() .update(cx, |codegen, cx| codegen.set_active(false, cx)); self.seen_alternatives.insert(index); @@ -2489,7 +2584,7 @@ impl Codegen { &mut self, user_prompt: String, assistant_panel_context: Option, - cx: &mut ModelContext, + cx: &mut Context, ) -> Result<()> { let alternative_models = LanguageModelRegistry::read_global(cx) .inline_alternative_models() @@ -2501,7 +2596,7 @@ impl Codegen { self.alternatives.truncate(1); for _ in 0..alternative_models.len() { - self.alternatives.push(cx.new_model(|cx| { + self.alternatives.push(cx.new(|cx| { CodegenAlternative::new( self.buffer.clone(), self.range.clone(), @@ -2534,13 +2629,13 @@ impl Codegen { Ok(()) } - pub fn stop(&mut self, cx: &mut ModelContext) { + pub fn stop(&mut self, cx: &mut Context) { for codegen in &self.alternatives { codegen.update(cx, |codegen, cx| codegen.stop(cx)); } } - pub fn undo(&mut self, cx: &mut ModelContext) { + pub fn undo(&mut self, cx: &mut Context) { self.active_alternative() .update(cx, |codegen, cx| codegen.undo(cx)); @@ -2556,34 +2651,34 @@ impl Codegen { &self, user_prompt: String, assistant_panel_context: Option, - cx: &AppContext, + cx: &App, ) -> BoxFuture<'static, Result> { self.active_alternative() .read(cx) .count_tokens(user_prompt, assistant_panel_context, cx) } - pub fn buffer(&self, cx: &AppContext) -> Model { + pub fn buffer(&self, cx: &App) -> Entity { self.active_alternative().read(cx).buffer.clone() } - pub fn old_buffer(&self, cx: &AppContext) -> Model { + pub fn old_buffer(&self, cx: &App) -> Entity { self.active_alternative().read(cx).old_buffer.clone() } - pub fn snapshot(&self, cx: &AppContext) -> MultiBufferSnapshot { + pub fn snapshot(&self, cx: &App) -> MultiBufferSnapshot { self.active_alternative().read(cx).snapshot.clone() } - pub fn edit_position(&self, cx: &AppContext) -> Option { + pub fn edit_position(&self, cx: &App) -> Option { self.active_alternative().read(cx).edit_position } - fn diff<'a>(&self, cx: &'a AppContext) -> &'a Diff { + fn diff<'a>(&self, cx: &'a App) -> &'a Diff { &self.active_alternative().read(cx).diff } - pub fn last_equal_ranges<'a>(&self, cx: &'a AppContext) -> &'a [Range] { + pub fn last_equal_ranges<'a>(&self, cx: &'a App) -> &'a [Range] { self.active_alternative().read(cx).last_equal_ranges() } } @@ -2591,8 +2686,8 @@ impl Codegen { impl EventEmitter for Codegen {} pub struct CodegenAlternative { - buffer: Model, - old_buffer: Model, + buffer: Entity, + old_buffer: Entity, snapshot: MultiBufferSnapshot, edit_position: Option, range: Range, @@ -2636,12 +2731,12 @@ impl EventEmitter for CodegenAlternative {} impl CodegenAlternative { pub fn new( - multi_buffer: Model, + multi_buffer: Entity, range: Range, active: bool, telemetry: Option>, builder: Arc, - cx: &mut ModelContext, + cx: &mut Context, ) -> Self { let snapshot = multi_buffer.read(cx).snapshot(cx); @@ -2649,7 +2744,7 @@ impl CodegenAlternative { .range_to_buffer_ranges(range.clone()) .pop() .unwrap(); - let old_buffer = cx.new_model(|cx| { + let old_buffer = cx.new(|cx| { let text = buffer.as_rope().clone(); let line_ending = buffer.line_ending(); let language = buffer.language().cloned(); @@ -2692,7 +2787,7 @@ impl CodegenAlternative { } } - fn set_active(&mut self, active: bool, cx: &mut ModelContext) { + fn set_active(&mut self, active: bool, cx: &mut Context) { if active != self.active { self.active = active; @@ -2716,9 +2811,9 @@ impl CodegenAlternative { fn handle_buffer_event( &mut self, - _buffer: Model, + _buffer: Entity, event: &multi_buffer::Event, - cx: &mut ModelContext, + cx: &mut Context, ) { if let multi_buffer::Event::TransactionUndone { transaction_id } = event { if self.transformation_transaction_id == Some(*transaction_id) { @@ -2737,7 +2832,7 @@ impl CodegenAlternative { &self, user_prompt: String, assistant_panel_context: Option, - cx: &AppContext, + cx: &App, ) -> BoxFuture<'static, Result> { if let Some(model) = LanguageModelRegistry::read_global(cx).active_model() { let request = self.build_request(user_prompt, assistant_panel_context.clone(), cx); @@ -2768,7 +2863,7 @@ impl CodegenAlternative { user_prompt: String, assistant_panel_context: Option, model: Arc, - cx: &mut ModelContext, + cx: &mut Context, ) -> Result<()> { if let Some(transformation_transaction_id) = self.transformation_transaction_id.take() { self.buffer.update(cx, |buffer, cx| { @@ -2799,7 +2894,7 @@ impl CodegenAlternative { &self, user_prompt: String, assistant_panel_context: Option, - cx: &AppContext, + cx: &App, ) -> Result { let buffer = self.buffer.read(cx).snapshot(cx); let language = buffer.language_at(self.range.start); @@ -2858,7 +2953,7 @@ impl CodegenAlternative { model_provider_id: String, model_api_key: Option, stream: impl 'static + Future>, - cx: &mut ModelContext, + cx: &mut Context, ) { let start_time = Instant::now(); let snapshot = self.snapshot.clone(); @@ -3116,7 +3211,7 @@ impl CodegenAlternative { cx.notify(); } - pub fn stop(&mut self, cx: &mut ModelContext) { + pub fn stop(&mut self, cx: &mut Context) { self.last_equal_ranges.clear(); if self.diff.is_empty() { self.status = CodegenStatus::Idle; @@ -3128,7 +3223,7 @@ impl CodegenAlternative { cx.notify(); } - pub fn undo(&mut self, cx: &mut ModelContext) { + pub fn undo(&mut self, cx: &mut Context) { self.buffer.update(cx, |buffer, cx| { if let Some(transaction_id) = self.transformation_transaction_id.take() { buffer.undo_transaction(transaction_id, cx); @@ -3140,7 +3235,7 @@ impl CodegenAlternative { fn apply_edits( &mut self, edits: impl IntoIterator, String)>, - cx: &mut ModelContext, + cx: &mut Context, ) { let transaction = self.buffer.update(cx, |buffer, cx| { // Avoid grouping assistant edits with user edits. @@ -3167,7 +3262,7 @@ impl CodegenAlternative { fn reapply_line_based_diff( &mut self, line_operations: impl IntoIterator, - cx: &mut ModelContext, + cx: &mut Context, ) { let old_snapshot = self.snapshot.clone(); let old_range = self.range.to_point(&old_snapshot); @@ -3223,7 +3318,7 @@ impl CodegenAlternative { } } - fn reapply_batch_diff(&mut self, cx: &mut ModelContext) -> Task<()> { + fn reapply_batch_diff(&mut self, cx: &mut Context) -> Task<()> { let old_snapshot = self.snapshot.clone(); let old_range = self.range.to_point(&old_snapshot); let new_snapshot = self.buffer.read(cx).snapshot(cx); @@ -3442,8 +3537,8 @@ where } struct AssistantCodeActionProvider { - editor: WeakView, - workspace: WeakView, + editor: WeakEntity, + workspace: WeakEntity, } const ASSISTANT_CODE_ACTION_PROVIDER_ID: &str = "assistant"; @@ -3455,9 +3550,10 @@ impl CodeActionProvider for AssistantCodeActionProvider { fn code_actions( &self, - buffer: &Model, + buffer: &Entity, range: Range, - cx: &mut WindowContext, + _: &mut Window, + cx: &mut App, ) -> Task>> { if !AssistantSettings::get_global(cx).enabled { return Task::ready(Ok(Vec::new())); @@ -3506,15 +3602,16 @@ impl CodeActionProvider for AssistantCodeActionProvider { fn apply_code_action( &self, - buffer: Model, + buffer: Entity, action: CodeAction, excerpt_id: ExcerptId, _push_to_history: bool, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Task> { let editor = self.editor.clone(); let workspace = self.workspace.clone(); - cx.spawn(|mut cx| async move { + window.spawn(cx, |mut cx| async move { let editor = editor.upgrade().context("editor was released")?; let range = editor .update(&mut cx, |editor, cx| { @@ -3558,7 +3655,7 @@ impl CodeActionProvider for AssistantCodeActionProvider { .context("assistant panel was released") })??; - cx.update_global(|assistant: &mut InlineAssistant, cx| { + cx.update_global(|assistant: &mut InlineAssistant, window, cx| { let assist_id = assistant.suggest_assist( &editor, range, @@ -3567,9 +3664,10 @@ impl CodeActionProvider for AssistantCodeActionProvider { true, Some(workspace), Some(&assistant_panel), + window, cx, ); - assistant.start_assist(assist_id, cx); + assistant.start_assist(assist_id, window, cx); })?; Ok(ProjectTransaction::default()) @@ -3607,7 +3705,7 @@ fn merge_ranges(ranges: &mut Vec>, buffer: &MultiBufferSnapshot) { mod tests { use super::*; use futures::stream::{self}; - use gpui::{Context, TestAppContext}; + use gpui::TestAppContext; use indoc::indoc; use language::{ language_settings, tree_sitter_rust, Buffer, Language, LanguageConfig, LanguageMatcher, @@ -3638,15 +3736,14 @@ mod tests { } } "}; - let buffer = - cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); let range = buffer.read_with(cx, |buffer, cx| { let snapshot = buffer.snapshot(cx); snapshot.anchor_before(Point::new(1, 0))..snapshot.anchor_after(Point::new(4, 5)) }); let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); - let codegen = cx.new_model(|cx| { + let codegen = cx.new(|cx| { CodegenAlternative::new( buffer.clone(), range.clone(), @@ -3702,15 +3799,14 @@ mod tests { le } "}; - let buffer = - cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); let range = buffer.read_with(cx, |buffer, cx| { let snapshot = buffer.snapshot(cx); snapshot.anchor_before(Point::new(1, 6))..snapshot.anchor_after(Point::new(1, 6)) }); let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); - let codegen = cx.new_model(|cx| { + let codegen = cx.new(|cx| { CodegenAlternative::new( buffer.clone(), range.clone(), @@ -3769,15 +3865,14 @@ mod tests { " \n", "}\n" // ); - let buffer = - cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); let range = buffer.read_with(cx, |buffer, cx| { let snapshot = buffer.snapshot(cx); snapshot.anchor_before(Point::new(1, 2))..snapshot.anchor_after(Point::new(1, 2)) }); let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); - let codegen = cx.new_model(|cx| { + let codegen = cx.new(|cx| { CodegenAlternative::new( buffer.clone(), range.clone(), @@ -3836,14 +3931,14 @@ mod tests { \t} } "}; - let buffer = cx.new_model(|cx| Buffer::local(text, cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); let range = buffer.read_with(cx, |buffer, cx| { let snapshot = buffer.snapshot(cx); snapshot.anchor_before(Point::new(0, 0))..snapshot.anchor_after(Point::new(4, 2)) }); let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); - let codegen = cx.new_model(|cx| { + let codegen = cx.new(|cx| { CodegenAlternative::new( buffer.clone(), range.clone(), @@ -3890,15 +3985,14 @@ mod tests { let x = 0; } "}; - let buffer = - cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); let range = buffer.read_with(cx, |buffer, cx| { let snapshot = buffer.snapshot(cx); snapshot.anchor_before(Point::new(1, 0))..snapshot.anchor_after(Point::new(1, 14)) }); let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); - let codegen = cx.new_model(|cx| { + let codegen = cx.new(|cx| { CodegenAlternative::new( buffer.clone(), range.clone(), @@ -3984,7 +4078,7 @@ mod tests { } fn simulate_response_stream( - codegen: Model, + codegen: Entity, cx: &mut TestAppContext, ) -> mpsc::UnboundedSender { let (chunks_tx, chunks_rx) = mpsc::unbounded(); diff --git a/crates/assistant/src/slash_command_settings.rs b/crates/assistant/src/slash_command_settings.rs index 5918769d71..25d575ed53 100644 --- a/crates/assistant/src/slash_command_settings.rs +++ b/crates/assistant/src/slash_command_settings.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use gpui::AppContext; +use gpui::App; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use settings::{Settings, SettingsSources}; @@ -36,7 +36,7 @@ impl Settings for SlashCommandSettings { type FileContent = Self; - fn load(sources: SettingsSources, _cx: &mut AppContext) -> Result { + fn load(sources: SettingsSources, _cx: &mut App) -> Result { SettingsSources::::json_merge_with( [sources.default] .into_iter() diff --git a/crates/assistant/src/terminal_inline_assistant.rs b/crates/assistant/src/terminal_inline_assistant.rs index ee48e7ea0e..6f2bb6fdba 100644 --- a/crates/assistant/src/terminal_inline_assistant.rs +++ b/crates/assistant/src/terminal_inline_assistant.rs @@ -11,8 +11,8 @@ use editor::{ use fs::Fs; use futures::{channel::mpsc, SinkExt, StreamExt}; use gpui::{ - AppContext, Context, EventEmitter, FocusHandle, FocusableView, Global, Model, ModelContext, - Subscription, Task, TextStyle, UpdateGlobal, View, WeakView, + App, Context, Entity, EventEmitter, FocusHandle, Focusable, Global, Subscription, Task, + TextStyle, UpdateGlobal, WeakEntity, }; use language::Buffer; use language_model::{ @@ -39,7 +39,7 @@ pub fn init( fs: Arc, prompt_builder: Arc, telemetry: Arc, - cx: &mut AppContext, + cx: &mut App, ) { cx.set_global(TerminalInlineAssistant::new(fs, prompt_builder, telemetry)); } @@ -86,20 +86,20 @@ impl TerminalInlineAssistant { pub fn assist( &mut self, - terminal_view: &View, - workspace: Option>, - assistant_panel: Option<&View>, + terminal_view: &Entity, + workspace: Option>, + assistant_panel: Option<&Entity>, initial_prompt: Option, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { let terminal = terminal_view.read(cx).terminal().clone(); let assist_id = self.next_assist_id.post_inc(); - let prompt_buffer = - cx.new_model(|cx| Buffer::local(initial_prompt.unwrap_or_default(), cx)); - let prompt_buffer = cx.new_model(|cx| MultiBuffer::singleton(prompt_buffer, cx)); - let codegen = cx.new_model(|_| Codegen::new(terminal, self.telemetry.clone())); + let prompt_buffer = cx.new(|cx| Buffer::local(initial_prompt.unwrap_or_default(), cx)); + let prompt_buffer = cx.new(|cx| MultiBuffer::singleton(prompt_buffer, cx)); + let codegen = cx.new(|_| Codegen::new(terminal, self.telemetry.clone())); - let prompt_editor = cx.new_view(|cx| { + let prompt_editor = cx.new(|cx| { PromptEditor::new( assist_id, self.prompt_history.clone(), @@ -108,6 +108,7 @@ impl TerminalInlineAssistant { assistant_panel, workspace.clone(), self.fs.clone(), + window, cx, ) }); @@ -117,7 +118,7 @@ impl TerminalInlineAssistant { render: Box::new(move |_| prompt_editor_render.clone().into_any_element()), }; terminal_view.update(cx, |terminal_view, cx| { - terminal_view.set_block_below_cursor(block, cx); + terminal_view.set_block_below_cursor(block, window, cx); }); let terminal_assistant = TerminalInlineAssist::new( @@ -126,21 +127,27 @@ impl TerminalInlineAssistant { assistant_panel.is_some(), prompt_editor, workspace.clone(), + window, cx, ); self.assists.insert(assist_id, terminal_assistant); - self.focus_assist(assist_id, cx); + self.focus_assist(assist_id, window, cx); } - fn focus_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut WindowContext) { + fn focus_assist( + &mut self, + assist_id: TerminalInlineAssistId, + window: &mut Window, + cx: &mut App, + ) { let assist = &self.assists[&assist_id]; if let Some(prompt_editor) = assist.prompt_editor.as_ref() { prompt_editor.update(cx, |this, cx| { this.editor.update(cx, |editor, cx| { - editor.focus(cx); - editor.select_all(&SelectAll, cx); + window.focus(&editor.focus_handle(cx)); + editor.select_all(&SelectAll, window, cx); }); }); } @@ -148,9 +155,10 @@ impl TerminalInlineAssistant { fn handle_prompt_editor_event( &mut self, - prompt_editor: View, + prompt_editor: Entity, event: &PromptEditorEvent, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { let assist_id = prompt_editor.read(cx).id; match event { @@ -161,21 +169,21 @@ impl TerminalInlineAssistant { self.stop_assist(assist_id, cx); } PromptEditorEvent::ConfirmRequested { execute } => { - self.finish_assist(assist_id, false, *execute, cx); + self.finish_assist(assist_id, false, *execute, window, cx); } PromptEditorEvent::CancelRequested => { - self.finish_assist(assist_id, true, false, cx); + self.finish_assist(assist_id, true, false, window, cx); } PromptEditorEvent::DismissRequested => { - self.dismiss_assist(assist_id, cx); + self.dismiss_assist(assist_id, window, cx); } PromptEditorEvent::Resized { height_in_lines } => { - self.insert_prompt_editor_into_terminal(assist_id, *height_in_lines, cx); + self.insert_prompt_editor_into_terminal(assist_id, *height_in_lines, window, cx); } } } - fn start_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut WindowContext) { + fn start_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut App) { let assist = if let Some(assist) = self.assists.get_mut(&assist_id) { assist } else { @@ -213,7 +221,7 @@ impl TerminalInlineAssistant { codegen.update(cx, |codegen, cx| codegen.start(request, cx)); } - fn stop_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut WindowContext) { + fn stop_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut App) { let assist = if let Some(assist) = self.assists.get_mut(&assist_id) { assist } else { @@ -226,7 +234,7 @@ impl TerminalInlineAssistant { fn request_for_inline_assist( &self, assist_id: TerminalInlineAssistId, - cx: &mut WindowContext, + cx: &mut App, ) -> Result { let assist = self.assists.get(&assist_id).context("invalid assist")?; @@ -296,16 +304,17 @@ impl TerminalInlineAssistant { assist_id: TerminalInlineAssistId, undo: bool, execute: bool, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { - self.dismiss_assist(assist_id, cx); + self.dismiss_assist(assist_id, window, cx); if let Some(assist) = self.assists.remove(&assist_id) { assist .terminal .update(cx, |this, cx| { this.clear_block_below_cursor(cx); - this.focus_handle(cx).focus(cx); + this.focus_handle(cx).focus(window); }) .log_err(); @@ -348,7 +357,8 @@ impl TerminalInlineAssistant { fn dismiss_assist( &mut self, assist_id: TerminalInlineAssistId, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> bool { let Some(assist) = self.assists.get_mut(&assist_id) else { return false; @@ -361,7 +371,7 @@ impl TerminalInlineAssistant { .terminal .update(cx, |this, cx| { this.clear_block_below_cursor(cx); - this.focus_handle(cx).focus(cx); + this.focus_handle(cx).focus(window); }) .is_ok() } @@ -370,7 +380,8 @@ impl TerminalInlineAssistant { &mut self, assist_id: TerminalInlineAssistId, height: u8, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { if let Some(assist) = self.assists.get_mut(&assist_id) { if let Some(prompt_editor) = assist.prompt_editor.as_ref().cloned() { @@ -382,7 +393,7 @@ impl TerminalInlineAssistant { height, render: Box::new(move |_| prompt_editor.clone().into_any_element()), }; - terminal.set_block_below_cursor(block, cx); + terminal.set_block_below_cursor(block, window, cx); }) .log_err(); } @@ -391,10 +402,10 @@ impl TerminalInlineAssistant { } struct TerminalInlineAssist { - terminal: WeakView, - prompt_editor: Option>, - codegen: Model, - workspace: Option>, + terminal: WeakEntity, + prompt_editor: Option>, + codegen: Entity, + workspace: Option>, include_context: bool, _subscriptions: Vec, } @@ -402,11 +413,12 @@ struct TerminalInlineAssist { impl TerminalInlineAssist { pub fn new( assist_id: TerminalInlineAssistId, - terminal: &View, + terminal: &Entity, include_context: bool, - prompt_editor: View, - workspace: Option>, - cx: &mut WindowContext, + prompt_editor: Entity, + workspace: Option>, + window: &mut Window, + cx: &mut App, ) -> Self { let codegen = prompt_editor.read(cx).codegen.clone(); Self { @@ -416,12 +428,12 @@ impl TerminalInlineAssist { workspace: workspace.clone(), include_context, _subscriptions: vec![ - cx.subscribe(&prompt_editor, |prompt_editor, event, cx| { + window.subscribe(&prompt_editor, cx, |prompt_editor, event, window, cx| { TerminalInlineAssistant::update_global(cx, |this, cx| { - this.handle_prompt_editor_event(prompt_editor, event, cx) + this.handle_prompt_editor_event(prompt_editor, event, window, cx) }) }), - cx.subscribe(&codegen, move |codegen, event, cx| { + window.subscribe(&codegen, cx, move |codegen, event, window, cx| { TerminalInlineAssistant::update_global(cx, |this, cx| match event { CodegenEvent::Finished => { let assist = if let Some(assist) = this.assists.get(&assist_id) { @@ -454,7 +466,7 @@ impl TerminalInlineAssist { } if assist.prompt_editor.is_none() { - this.finish_assist(assist_id, false, false, cx); + this.finish_assist(assist_id, false, false, window, cx); } } }) @@ -476,25 +488,25 @@ enum PromptEditorEvent { struct PromptEditor { id: TerminalInlineAssistId, height_in_lines: u8, - editor: View, - language_model_selector: View, + editor: Entity, + language_model_selector: Entity, edited_since_done: bool, prompt_history: VecDeque, prompt_history_ix: Option, pending_prompt: String, - codegen: Model, + codegen: Entity, _codegen_subscription: Subscription, editor_subscriptions: Vec, pending_token_count: Task>, token_count: Option, _token_count_subscriptions: Vec, - workspace: Option>, + workspace: Option>, } impl EventEmitter for PromptEditor {} impl Render for PromptEditor { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { let status = &self.codegen.read(cx).status; let buttons = match status { CodegenStatus::Idle => { @@ -502,16 +514,20 @@ impl Render for PromptEditor { IconButton::new("cancel", IconName::Close) .icon_color(Color::Muted) .shape(IconButtonShape::Square) - .tooltip(|cx| Tooltip::for_action("Cancel Assist", &menu::Cancel, cx)) + .tooltip(|window, cx| { + Tooltip::for_action("Cancel Assist", &menu::Cancel, window, cx) + }) .on_click( - cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::CancelRequested)), + cx.listener(|_, _, _, cx| cx.emit(PromptEditorEvent::CancelRequested)), ), IconButton::new("start", IconName::SparkleAlt) .icon_color(Color::Muted) .shape(IconButtonShape::Square) - .tooltip(|cx| Tooltip::for_action("Generate", &menu::Confirm, cx)) + .tooltip(|window, cx| { + Tooltip::for_action("Generate", &menu::Confirm, window, cx) + }) .on_click( - cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::StartRequested)), + cx.listener(|_, _, _, cx| cx.emit(PromptEditorEvent::StartRequested)), ), ] } @@ -520,23 +536,24 @@ impl Render for PromptEditor { IconButton::new("cancel", IconName::Close) .icon_color(Color::Muted) .shape(IconButtonShape::Square) - .tooltip(|cx| Tooltip::text("Cancel Assist", cx)) + .tooltip(Tooltip::text("Cancel Assist")) .on_click( - cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::CancelRequested)), + cx.listener(|_, _, _, cx| cx.emit(PromptEditorEvent::CancelRequested)), ), IconButton::new("stop", IconName::Stop) .icon_color(Color::Error) .shape(IconButtonShape::Square) - .tooltip(|cx| { + .tooltip(|window, cx| { Tooltip::with_meta( "Interrupt Generation", Some(&menu::Cancel), "Changes won't be discarded", + window, cx, ) }) .on_click( - cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::StopRequested)), + cx.listener(|_, _, _, cx| cx.emit(PromptEditorEvent::StopRequested)), ), ] } @@ -544,8 +561,12 @@ impl Render for PromptEditor { let cancel = IconButton::new("cancel", IconName::Close) .icon_color(Color::Muted) .shape(IconButtonShape::Square) - .tooltip(|cx| Tooltip::for_action("Cancel Assist", &menu::Cancel, cx)) - .on_click(cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::CancelRequested))); + .tooltip(|window, cx| { + Tooltip::for_action("Cancel Assist", &menu::Cancel, window, cx) + }) + .on_click( + cx.listener(|_, _, _, cx| cx.emit(PromptEditorEvent::CancelRequested)), + ); let has_error = matches!(status, CodegenStatus::Error(_)); if has_error || self.edited_since_done { @@ -554,15 +575,16 @@ impl Render for PromptEditor { IconButton::new("restart", IconName::RotateCw) .icon_color(Color::Info) .shape(IconButtonShape::Square) - .tooltip(|cx| { + .tooltip(|window, cx| { Tooltip::with_meta( "Restart Generation", Some(&menu::Confirm), "Changes will be discarded", + window, cx, ) }) - .on_click(cx.listener(|_, _, cx| { + .on_click(cx.listener(|_, _, _, cx| { cx.emit(PromptEditorEvent::StartRequested); })), ] @@ -572,23 +594,29 @@ impl Render for PromptEditor { IconButton::new("accept", IconName::Check) .icon_color(Color::Info) .shape(IconButtonShape::Square) - .tooltip(|cx| { - Tooltip::for_action("Accept Generated Command", &menu::Confirm, cx) + .tooltip(|window, cx| { + Tooltip::for_action( + "Accept Generated Command", + &menu::Confirm, + window, + cx, + ) }) - .on_click(cx.listener(|_, _, cx| { + .on_click(cx.listener(|_, _, _, cx| { cx.emit(PromptEditorEvent::ConfirmRequested { execute: false }); })), IconButton::new("confirm", IconName::Play) .icon_color(Color::Info) .shape(IconButtonShape::Square) - .tooltip(|cx| { + .tooltip(|window, cx| { Tooltip::for_action( "Execute Generated Command", &menu::SecondaryConfirm, + window, cx, ) }) - .on_click(cx.listener(|_, _, cx| { + .on_click(cx.listener(|_, _, _, cx| { cx.emit(PromptEditorEvent::ConfirmRequested { execute: true }); })), ] @@ -619,7 +647,7 @@ impl Render for PromptEditor { .shape(IconButtonShape::Square) .icon_size(IconSize::Small) .icon_color(Color::Muted) - .tooltip(move |cx| { + .tooltip(move |window, cx| { Tooltip::with_meta( format!( "Using {}", @@ -630,6 +658,7 @@ impl Render for PromptEditor { ), None, "Change Model", + window, cx, ) }), @@ -640,7 +669,7 @@ impl Render for PromptEditor { Some( div() .id("error") - .tooltip(move |cx| Tooltip::text(error_message.clone(), cx)) + .tooltip(Tooltip::text(error_message)) .child( Icon::new(IconName::XCircle) .size(IconSize::Small) @@ -663,8 +692,8 @@ impl Render for PromptEditor { } } -impl FocusableView for PromptEditor { - fn focus_handle(&self, cx: &AppContext) -> FocusHandle { +impl Focusable for PromptEditor { + fn focus_handle(&self, cx: &App) -> FocusHandle { self.editor.focus_handle(cx) } } @@ -676,14 +705,15 @@ impl PromptEditor { fn new( id: TerminalInlineAssistId, prompt_history: VecDeque, - prompt_buffer: Model, - codegen: Model, - assistant_panel: Option<&View>, - workspace: Option>, + prompt_buffer: Entity, + codegen: Entity, + assistant_panel: Option<&Entity>, + workspace: Option>, fs: Arc, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Self { - let prompt_editor = cx.new_view(|cx| { + let prompt_editor = cx.new(|cx| { let mut editor = Editor::new( EditorMode::AutoHeight { max_lines: Self::MAX_LINES as usize, @@ -691,24 +721,28 @@ impl PromptEditor { prompt_buffer, None, false, + window, cx, ); editor.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx); - editor.set_placeholder_text(Self::placeholder_text(cx), cx); + editor.set_placeholder_text(Self::placeholder_text(window), cx); editor }); let mut token_count_subscriptions = Vec::new(); if let Some(assistant_panel) = assistant_panel { - token_count_subscriptions - .push(cx.subscribe(assistant_panel, Self::handle_assistant_panel_event)); + token_count_subscriptions.push(cx.subscribe_in( + assistant_panel, + window, + Self::handle_assistant_panel_event, + )); } let mut this = Self { id, height_in_lines: 1, editor: prompt_editor, - language_model_selector: cx.new_view(|cx| { + language_model_selector: cx.new(|cx| { let fs = fs.clone(); LanguageModelSelector::new( move |model, cx| { @@ -718,6 +752,7 @@ impl PromptEditor { move |settings, _| settings.set_model(model.clone()), ); }, + window, cx, ) }), @@ -725,7 +760,7 @@ impl PromptEditor { prompt_history, prompt_history_ix: None, pending_prompt: String::new(), - _codegen_subscription: cx.observe(&codegen, Self::handle_codegen_changed), + _codegen_subscription: cx.observe_in(&codegen, window, Self::handle_codegen_changed), editor_subscriptions: Vec::new(), codegen, pending_token_count: Task::ready(Ok(())), @@ -739,15 +774,15 @@ impl PromptEditor { this } - fn placeholder_text(cx: &WindowContext) -> String { - let context_keybinding = text_for_action(&zed_actions::assistant::ToggleFocus, cx) + fn placeholder_text(window: &Window) -> String { + let context_keybinding = text_for_action(&zed_actions::assistant::ToggleFocus, window) .map(|keybinding| format!(" • {keybinding} for context")) .unwrap_or_default(); format!("Generate…{context_keybinding} • ↓↑ for history") } - fn subscribe_to_editor(&mut self, cx: &mut ViewContext) { + fn subscribe_to_editor(&mut self, cx: &mut Context) { self.editor_subscriptions.clear(); self.editor_subscriptions .push(cx.observe(&self.editor, Self::handle_prompt_editor_changed)); @@ -755,11 +790,11 @@ impl PromptEditor { .push(cx.subscribe(&self.editor, Self::handle_prompt_editor_events)); } - fn prompt(&self, cx: &AppContext) -> String { + fn prompt(&self, cx: &App) -> String { self.editor.read(cx).text(cx) } - fn count_lines(&mut self, cx: &mut ViewContext) { + fn count_lines(&mut self, cx: &mut Context) { let height_in_lines = cmp::max( 2, // Make the editor at least two lines tall, to account for padding and buttons. cmp::min( @@ -777,15 +812,16 @@ impl PromptEditor { fn handle_assistant_panel_event( &mut self, - _: View, + _: &Entity, event: &AssistantPanelEvent, - cx: &mut ViewContext, + _: &mut Window, + cx: &mut Context, ) { let AssistantPanelEvent::ContextEdited { .. } = event; self.count_tokens(cx); } - fn count_tokens(&mut self, cx: &mut ViewContext) { + fn count_tokens(&mut self, cx: &mut Context) { let assist_id = self.id; let Some(model) = LanguageModelRegistry::read_global(cx).active_model() else { return; @@ -805,15 +841,15 @@ impl PromptEditor { }) } - fn handle_prompt_editor_changed(&mut self, _: View, cx: &mut ViewContext) { + fn handle_prompt_editor_changed(&mut self, _: Entity, cx: &mut Context) { self.count_lines(cx); } fn handle_prompt_editor_events( &mut self, - _: View, + _: Entity, event: &EditorEvent, - cx: &mut ViewContext, + cx: &mut Context, ) { match event { EditorEvent::Edited { .. } => { @@ -836,7 +872,12 @@ impl PromptEditor { } } - fn handle_codegen_changed(&mut self, _: Model, cx: &mut ViewContext) { + fn handle_codegen_changed( + &mut self, + _: Entity, + _: &mut Window, + cx: &mut Context, + ) { match &self.codegen.read(cx).status { CodegenStatus::Idle => { self.editor @@ -854,7 +895,7 @@ impl PromptEditor { } } - fn cancel(&mut self, _: &editor::actions::Cancel, cx: &mut ViewContext) { + fn cancel(&mut self, _: &editor::actions::Cancel, _: &mut Window, cx: &mut Context) { match &self.codegen.read(cx).status { CodegenStatus::Idle | CodegenStatus::Done | CodegenStatus::Error(_) => { cx.emit(PromptEditorEvent::CancelRequested); @@ -865,7 +906,7 @@ impl PromptEditor { } } - fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext) { + fn confirm(&mut self, _: &menu::Confirm, _: &mut Window, cx: &mut Context) { match &self.codegen.read(cx).status { CodegenStatus::Idle => { if !self.editor.read(cx).text(cx).trim().is_empty() { @@ -888,53 +929,58 @@ impl PromptEditor { } } - fn secondary_confirm(&mut self, _: &menu::SecondaryConfirm, cx: &mut ViewContext) { + fn secondary_confirm( + &mut self, + _: &menu::SecondaryConfirm, + _: &mut Window, + cx: &mut Context, + ) { if matches!(self.codegen.read(cx).status, CodegenStatus::Done) { cx.emit(PromptEditorEvent::ConfirmRequested { execute: true }); } } - fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext) { + fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context) { if let Some(ix) = self.prompt_history_ix { if ix > 0 { self.prompt_history_ix = Some(ix - 1); let prompt = self.prompt_history[ix - 1].as_str(); self.editor.update(cx, |editor, cx| { - editor.set_text(prompt, cx); - editor.move_to_beginning(&Default::default(), cx); + editor.set_text(prompt, window, cx); + editor.move_to_beginning(&Default::default(), window, cx); }); } } else if !self.prompt_history.is_empty() { self.prompt_history_ix = Some(self.prompt_history.len() - 1); let prompt = self.prompt_history[self.prompt_history.len() - 1].as_str(); self.editor.update(cx, |editor, cx| { - editor.set_text(prompt, cx); - editor.move_to_beginning(&Default::default(), cx); + editor.set_text(prompt, window, cx); + editor.move_to_beginning(&Default::default(), window, cx); }); } } - fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext) { + fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context) { if let Some(ix) = self.prompt_history_ix { if ix < self.prompt_history.len() - 1 { self.prompt_history_ix = Some(ix + 1); let prompt = self.prompt_history[ix + 1].as_str(); self.editor.update(cx, |editor, cx| { - editor.set_text(prompt, cx); - editor.move_to_end(&Default::default(), cx) + editor.set_text(prompt, window, cx); + editor.move_to_end(&Default::default(), window, cx) }); } else { self.prompt_history_ix = None; let prompt = self.pending_prompt.as_str(); self.editor.update(cx, |editor, cx| { - editor.set_text(prompt, cx); - editor.move_to_end(&Default::default(), cx) + editor.set_text(prompt, window, cx); + editor.move_to_end(&Default::default(), window, cx) }); } } } - fn render_token_count(&self, cx: &mut ViewContext) -> Option { + fn render_token_count(&self, cx: &mut Context) -> Option { let model = LanguageModelRegistry::read_global(cx).active_model()?; let token_count = self.token_count?; let max_token_count = model.max_token_count(); @@ -964,34 +1010,35 @@ impl PromptEditor { ); if let Some(workspace) = self.workspace.clone() { token_count = token_count - .tooltip(|cx| { + .tooltip(|window, cx| { Tooltip::with_meta( "Tokens Used by Inline Assistant", None, "Click to Open Assistant Panel", + window, cx, ) }) .cursor_pointer() - .on_mouse_down(gpui::MouseButton::Left, |_, cx| cx.stop_propagation()) - .on_click(move |_, cx| { + .on_mouse_down(gpui::MouseButton::Left, |_, _, cx| cx.stop_propagation()) + .on_click(move |_, window, cx| { cx.stop_propagation(); workspace .update(cx, |workspace, cx| { - workspace.focus_panel::(cx) + workspace.focus_panel::(window, cx) }) .ok(); }); } else { token_count = token_count .cursor_default() - .tooltip(|cx| Tooltip::text("Tokens Used by Inline Assistant", cx)); + .tooltip(Tooltip::text("Tokens Used by Inline Assistant")); } Some(token_count) } - fn render_prompt_editor(&self, cx: &mut ViewContext) -> impl IntoElement { + fn render_prompt_editor(&self, cx: &mut Context) -> impl IntoElement { let settings = ThemeSettings::get_global(cx); let text_style = TextStyle { color: if self.editor.read(cx).read_only(cx) { @@ -1029,27 +1076,27 @@ const CLEAR_INPUT: &str = "\x15"; const CARRIAGE_RETURN: &str = "\x0d"; struct TerminalTransaction { - terminal: Model, + terminal: Entity, } impl TerminalTransaction { - pub fn start(terminal: Model) -> Self { + pub fn start(terminal: Entity) -> Self { Self { terminal } } - pub fn push(&mut self, hunk: String, cx: &mut AppContext) { + pub fn push(&mut self, hunk: String, cx: &mut App) { // Ensure that the assistant cannot accidentally execute commands that are streamed into the terminal let input = Self::sanitize_input(hunk); self.terminal .update(cx, |terminal, _| terminal.input(input)); } - pub fn undo(&self, cx: &mut AppContext) { + pub fn undo(&self, cx: &mut App) { self.terminal .update(cx, |terminal, _| terminal.input(CLEAR_INPUT.to_string())); } - pub fn complete(&self, cx: &mut AppContext) { + pub fn complete(&self, cx: &mut App) { self.terminal.update(cx, |terminal, _| { terminal.input(CARRIAGE_RETURN.to_string()) }); @@ -1063,14 +1110,14 @@ impl TerminalTransaction { pub struct Codegen { status: CodegenStatus, telemetry: Option>, - terminal: Model, + terminal: Entity, generation: Task<()>, message_id: Option, transaction: Option, } impl Codegen { - pub fn new(terminal: Model, telemetry: Option>) -> Self { + pub fn new(terminal: Entity, telemetry: Option>) -> Self { Self { terminal, telemetry, @@ -1081,7 +1128,7 @@ impl Codegen { } } - pub fn start(&mut self, prompt: LanguageModelRequest, cx: &mut ModelContext) { + pub fn start(&mut self, prompt: LanguageModelRequest, cx: &mut Context) { let Some(model) = LanguageModelRegistry::read_global(cx).active_model() else { return; }; @@ -1181,20 +1228,20 @@ impl Codegen { cx.notify(); } - pub fn stop(&mut self, cx: &mut ModelContext) { + pub fn stop(&mut self, cx: &mut Context) { self.status = CodegenStatus::Done; self.generation = Task::ready(()); cx.emit(CodegenEvent::Finished); cx.notify(); } - pub fn complete(&mut self, cx: &mut ModelContext) { + pub fn complete(&mut self, cx: &mut Context) { if let Some(transaction) = self.transaction.take() { transaction.complete(cx); } } - pub fn undo(&mut self, cx: &mut ModelContext) { + pub fn undo(&mut self, cx: &mut Context) { if let Some(transaction) = self.transaction.take() { transaction.undo(cx); } diff --git a/crates/assistant2/src/active_thread.rs b/crates/assistant2/src/active_thread.rs index 3f643fdc00..3cade8f003 100644 --- a/crates/assistant2/src/active_thread.rs +++ b/crates/assistant2/src/active_thread.rs @@ -3,9 +3,9 @@ use std::sync::Arc; use assistant_tool::ToolWorkingSet; use collections::HashMap; use gpui::{ - list, AbsoluteLength, AnyElement, AppContext, DefiniteLength, EdgesRefinement, Empty, Length, - ListAlignment, ListOffset, ListState, Model, StyleRefinement, Subscription, - TextStyleRefinement, UnderlineStyle, View, WeakView, + list, AbsoluteLength, AnyElement, App, DefiniteLength, EdgesRefinement, Empty, Entity, Length, + ListAlignment, ListOffset, ListState, StyleRefinement, Subscription, TextStyleRefinement, + UnderlineStyle, WeakEntity, }; use language::LanguageRegistry; use language_model::Role; @@ -20,30 +20,31 @@ use crate::thread_store::ThreadStore; use crate::ui::ContextPill; pub struct ActiveThread { - workspace: WeakView, + workspace: WeakEntity, language_registry: Arc, tools: Arc, - thread_store: Model, - thread: Model, + thread_store: Entity, + thread: Entity, messages: Vec, list_state: ListState, - rendered_messages_by_id: HashMap>, + rendered_messages_by_id: HashMap>, last_error: Option, _subscriptions: Vec, } impl ActiveThread { pub fn new( - thread: Model, - thread_store: Model, - workspace: WeakView, + thread: Entity, + thread_store: Entity, + workspace: WeakEntity, language_registry: Arc, tools: Arc, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Self { let subscriptions = vec![ cx.observe(&thread, |_, _, cx| cx.notify()), - cx.subscribe(&thread, Self::handle_thread_event), + cx.subscribe_in(&thread, window, Self::handle_thread_event), ]; let mut this = Self { @@ -55,8 +56,8 @@ impl ActiveThread { messages: Vec::new(), rendered_messages_by_id: HashMap::default(), list_state: ListState::new(0, ListAlignment::Bottom, px(1024.), { - let this = cx.view().downgrade(); - move |ix, cx: &mut WindowContext| { + let this = cx.model().downgrade(); + move |ix, _: &mut Window, cx: &mut App| { this.update(cx, |this, cx| this.render_message(ix, cx)) .unwrap() } @@ -66,13 +67,13 @@ impl ActiveThread { }; for message in thread.read(cx).messages().cloned().collect::>() { - this.push_message(&message.id, message.text.clone(), cx); + this.push_message(&message.id, message.text.clone(), window, cx); } this } - pub fn thread(&self) -> &Model { + pub fn thread(&self) -> &Entity { &self.thread } @@ -80,15 +81,15 @@ impl ActiveThread { self.messages.is_empty() } - pub fn summary(&self, cx: &AppContext) -> Option { + pub fn summary(&self, cx: &App) -> Option { self.thread.read(cx).summary() } - pub fn summary_or_default(&self, cx: &AppContext) -> SharedString { + pub fn summary_or_default(&self, cx: &App) -> SharedString { self.thread.read(cx).summary_or_default() } - pub fn cancel_last_completion(&mut self, cx: &mut AppContext) -> bool { + pub fn cancel_last_completion(&mut self, cx: &mut App) -> bool { self.last_error.take(); self.thread .update(cx, |thread, _cx| thread.cancel_last_completion()) @@ -102,7 +103,13 @@ impl ActiveThread { self.last_error.take(); } - fn push_message(&mut self, id: &MessageId, text: String, cx: &mut ViewContext) { + fn push_message( + &mut self, + id: &MessageId, + text: String, + window: &mut Window, + cx: &mut Context, + ) { let old_len = self.messages.len(); self.messages.push(*id); self.list_state.splice(old_len..old_len, 1); @@ -111,7 +118,7 @@ impl ActiveThread { let colors = cx.theme().colors(); let ui_font_size = TextSize::Default.rems(cx); let buffer_font_size = TextSize::Small.rems(cx); - let mut text_style = cx.text_style(); + let mut text_style = window.text_style(); text_style.refine(&TextStyleRefinement { font_family: Some(theme_settings.ui_font.family.clone()), @@ -170,12 +177,13 @@ impl ActiveThread { ..Default::default() }; - let markdown = cx.new_view(|cx| { + let markdown = cx.new(|cx| { Markdown::new( text, markdown_style, Some(self.language_registry.clone()), None, + window, cx, ) }); @@ -188,9 +196,10 @@ impl ActiveThread { fn handle_thread_event( &mut self, - _: Model, + _: &Entity, event: &ThreadEvent, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { match event { ThreadEvent::ShowError(error) => { @@ -206,7 +215,7 @@ impl ActiveThread { ThreadEvent::StreamedAssistantText(message_id, text) => { if let Some(markdown) = self.rendered_messages_by_id.get_mut(&message_id) { markdown.update(cx, |markdown, cx| { - markdown.append(text, cx); + markdown.append(text, window, cx); }); } } @@ -217,7 +226,7 @@ impl ActiveThread { .message(*message_id) .map(|message| message.text.clone()) { - self.push_message(message_id, message_text, cx); + self.push_message(message_id, message_text, window, cx); } self.thread_store @@ -240,7 +249,7 @@ impl ActiveThread { for tool_use in pending_tool_uses { if let Some(tool) = self.tools.tool(&tool_use.name, cx) { - let task = tool.run(tool_use.input, self.workspace.clone(), cx); + let task = tool.run(tool_use.input, self.workspace.clone(), window, cx); self.thread.update(cx, |thread, cx| { thread.insert_tool_output( @@ -257,7 +266,7 @@ impl ActiveThread { } } - fn render_message(&self, ix: usize, cx: &mut ViewContext) -> AnyElement { + fn render_message(&self, ix: usize, cx: &mut Context) -> AnyElement { let message_id = self.messages[ix]; let Some(message) = self.thread.read(cx).message(message_id) else { return Empty.into_any(); @@ -338,7 +347,7 @@ impl ActiveThread { } impl Render for ActiveThread { - fn render(&mut self, _cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { v_flex() .size_full() .pt_1p5() diff --git a/crates/assistant2/src/assistant.rs b/crates/assistant2/src/assistant.rs index fdea222fc8..0d1303ea90 100644 --- a/crates/assistant2/src/assistant.rs +++ b/crates/assistant2/src/assistant.rs @@ -24,7 +24,7 @@ use client::Client; use command_palette_hooks::CommandPaletteFilter; use feature_flags::{Assistant2FeatureFlag, FeatureFlagAppExt}; use fs::Fs; -use gpui::{actions, AppContext}; +use gpui::{actions, App}; use prompt_library::PromptBuilder; use settings::Settings as _; @@ -63,7 +63,7 @@ pub fn init( fs: Arc, client: Arc, prompt_builder: Arc, - cx: &mut AppContext, + cx: &mut App, ) { AssistantSettings::register(cx); assistant_panel::init(cx); @@ -84,7 +84,7 @@ pub fn init( feature_gate_assistant2_actions(cx); } -fn feature_gate_assistant2_actions(cx: &mut AppContext) { +fn feature_gate_assistant2_actions(cx: &mut App) { CommandPaletteFilter::update_global(cx, |filter, _cx| { filter.hide_namespace(NAMESPACE); }); diff --git a/crates/assistant2/src/assistant_configuration.rs b/crates/assistant2/src/assistant_configuration.rs index e44fa1833f..efecfe729a 100644 --- a/crates/assistant2/src/assistant_configuration.rs +++ b/crates/assistant2/src/assistant_configuration.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use collections::HashMap; -use gpui::{Action, AnyView, AppContext, EventEmitter, FocusHandle, FocusableView, Subscription}; +use gpui::{AnyView, App, EventEmitter, FocusHandle, Focusable, Subscription}; use language_model::{LanguageModelProvider, LanguageModelProviderId, LanguageModelRegistry}; use ui::{prelude::*, ElevationIndex}; use zed_actions::assistant::DeployPromptLibrary; @@ -13,16 +13,17 @@ pub struct AssistantConfiguration { } impl AssistantConfiguration { - pub fn new(cx: &mut ViewContext) -> Self { + pub fn new(window: &mut Window, cx: &mut Context) -> Self { let focus_handle = cx.focus_handle(); - let registry_subscription = cx.subscribe( + let registry_subscription = cx.subscribe_in( &LanguageModelRegistry::global(cx), - |this, _, event: &language_model::Event, cx| match event { + window, + |this, _, event: &language_model::Event, window, cx| match event { language_model::Event::AddedProvider(provider_id) => { let provider = LanguageModelRegistry::read_global(cx).provider(provider_id); if let Some(provider) = provider { - this.add_provider_configuration_view(&provider, cx); + this.add_provider_configuration_view(&provider, window, cx); } } language_model::Event::RemovedProvider(provider_id) => { @@ -37,14 +38,14 @@ impl AssistantConfiguration { configuration_views_by_provider: HashMap::default(), _registry_subscription: registry_subscription, }; - this.build_provider_configuration_views(cx); + this.build_provider_configuration_views(window, cx); this } - fn build_provider_configuration_views(&mut self, cx: &mut ViewContext) { + fn build_provider_configuration_views(&mut self, window: &mut Window, cx: &mut Context) { let providers = LanguageModelRegistry::read_global(cx).providers(); for provider in providers { - self.add_provider_configuration_view(&provider, cx); + self.add_provider_configuration_view(&provider, window, cx); } } @@ -55,16 +56,17 @@ impl AssistantConfiguration { fn add_provider_configuration_view( &mut self, provider: &Arc, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - let configuration_view = provider.configuration_view(cx); + let configuration_view = provider.configuration_view(window, cx); self.configuration_views_by_provider .insert(provider.id(), configuration_view); } } -impl FocusableView for AssistantConfiguration { - fn focus_handle(&self, _: &AppContext) -> FocusHandle { +impl Focusable for AssistantConfiguration { + fn focus_handle(&self, _: &App) -> FocusHandle { self.focus_handle.clone() } } @@ -79,7 +81,7 @@ impl AssistantConfiguration { fn render_provider_configuration( &mut self, provider: &Arc, - cx: &mut ViewContext, + cx: &mut Context, ) -> impl IntoElement { let provider_id = provider.id().0.clone(); let provider_name = provider.name().0.clone(); @@ -107,7 +109,7 @@ impl AssistantConfiguration { .layer(ElevationIndex::ModalSurface) .on_click(cx.listener({ let provider = provider.clone(); - move |_this, _event, cx| { + move |_this, _event, _window, cx| { cx.emit(AssistantConfigurationEvent::NewThread( provider.clone(), )) @@ -135,7 +137,7 @@ impl AssistantConfiguration { } impl Render for AssistantConfiguration { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { let providers = LanguageModelRegistry::read_global(cx).providers(); v_flex() @@ -152,9 +154,7 @@ impl Render for AssistantConfiguration { .icon(IconName::Book) .icon_size(IconSize::Small) .icon_position(IconPosition::Start) - .on_click(|_event, cx| { - cx.dispatch_action(DeployPromptLibrary.boxed_clone()) - }), + .on_click(|_event, _window, cx| cx.dispatch_action(&DeployPromptLibrary)), ), ) .child( diff --git a/crates/assistant2/src/assistant_model_selector.rs b/crates/assistant2/src/assistant_model_selector.rs index c31b6bcba3..c71e70d459 100644 --- a/crates/assistant2/src/assistant_model_selector.rs +++ b/crates/assistant2/src/assistant_model_selector.rs @@ -1,6 +1,6 @@ use assistant_settings::AssistantSettings; use fs::Fs; -use gpui::{FocusHandle, View}; +use gpui::{Entity, FocusHandle}; use language_model::LanguageModelRegistry; use language_model_selector::{LanguageModelSelector, LanguageModelSelectorPopoverMenu}; use settings::update_settings_file; @@ -10,7 +10,7 @@ use ui::{prelude::*, ButtonLike, PopoverMenuHandle, Tooltip}; use crate::ToggleModelSelector; pub struct AssistantModelSelector { - selector: View, + selector: Entity, menu_handle: PopoverMenuHandle, focus_handle: FocusHandle, } @@ -20,10 +20,11 @@ impl AssistantModelSelector { fs: Arc, menu_handle: PopoverMenuHandle, focus_handle: FocusHandle, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Self { Self { - selector: cx.new_view(|cx| { + selector: cx.new(|cx| { let fs = fs.clone(); LanguageModelSelector::new( move |model, cx| { @@ -33,6 +34,7 @@ impl AssistantModelSelector { move |settings, _cx| settings.set_model(model.clone()), ); }, + window, cx, ) }), @@ -43,7 +45,7 @@ impl AssistantModelSelector { } impl Render for AssistantModelSelector { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { let active_model = LanguageModelRegistry::read_global(cx).active_model(); let focus_handle = self.focus_handle.clone(); @@ -79,8 +81,14 @@ impl Render for AssistantModelSelector { .size(IconSize::XSmall), ), ) - .tooltip(move |cx| { - Tooltip::for_action_in("Change Model", &ToggleModelSelector, &focus_handle, cx) + .tooltip(move |window, cx| { + Tooltip::for_action_in( + "Change Model", + &ToggleModelSelector, + &focus_handle, + window, + cx, + ) }), ) .with_handle(self.menu_handle.clone()) diff --git a/crates/assistant2/src/assistant_panel.rs b/crates/assistant2/src/assistant_panel.rs index ad648bd54e..07593e8d75 100644 --- a/crates/assistant2/src/assistant_panel.rs +++ b/crates/assistant2/src/assistant_panel.rs @@ -14,9 +14,8 @@ use client::zed_urls; use editor::Editor; use fs::Fs; use gpui::{ - prelude::*, px, svg, Action, AnyElement, AppContext, AsyncWindowContext, Corner, EventEmitter, - FocusHandle, FocusableView, FontWeight, Model, Pixels, Subscription, Task, UpdateGlobal, View, - ViewContext, WeakView, WindowContext, + prelude::*, px, svg, Action, AnyElement, App, AsyncWindowContext, Corner, Entity, EventEmitter, + FocusHandle, Focusable, FontWeight, Pixels, Subscription, Task, UpdateGlobal, WeakEntity, }; use language::LanguageRegistry; use language_model::{LanguageModelProviderTosView, LanguageModelRegistry}; @@ -41,38 +40,38 @@ use crate::{ OpenPromptEditorHistory, }; -pub fn init(cx: &mut AppContext) { - cx.observe_new_views( - |workspace: &mut Workspace, _cx: &mut ViewContext| { +pub fn init(cx: &mut App) { + cx.observe_new( + |workspace: &mut Workspace, _window, _cx: &mut Context| { workspace - .register_action(|workspace, _: &NewThread, cx| { + .register_action(|workspace, _: &NewThread, window, cx| { if let Some(panel) = workspace.panel::(cx) { - panel.update(cx, |panel, cx| panel.new_thread(cx)); - workspace.focus_panel::(cx); + panel.update(cx, |panel, cx| panel.new_thread(window, cx)); + workspace.focus_panel::(window, cx); } }) - .register_action(|workspace, _: &OpenHistory, cx| { + .register_action(|workspace, _: &OpenHistory, window, cx| { if let Some(panel) = workspace.panel::(cx) { - workspace.focus_panel::(cx); - panel.update(cx, |panel, cx| panel.open_history(cx)); + workspace.focus_panel::(window, cx); + panel.update(cx, |panel, cx| panel.open_history(window, cx)); } }) - .register_action(|workspace, _: &NewPromptEditor, cx| { + .register_action(|workspace, _: &NewPromptEditor, window, cx| { if let Some(panel) = workspace.panel::(cx) { - workspace.focus_panel::(cx); - panel.update(cx, |panel, cx| panel.new_prompt_editor(cx)); + workspace.focus_panel::(window, cx); + panel.update(cx, |panel, cx| panel.new_prompt_editor(window, cx)); } }) - .register_action(|workspace, _: &OpenPromptEditorHistory, cx| { + .register_action(|workspace, _: &OpenPromptEditorHistory, window, cx| { if let Some(panel) = workspace.panel::(cx) { - workspace.focus_panel::(cx); - panel.update(cx, |panel, cx| panel.open_prompt_editor_history(cx)); + workspace.focus_panel::(window, cx); + panel.update(cx, |panel, cx| panel.open_prompt_editor_history(window, cx)); } }) - .register_action(|workspace, _: &OpenConfiguration, cx| { + .register_action(|workspace, _: &OpenConfiguration, window, cx| { if let Some(panel) = workspace.panel::(cx) { - workspace.focus_panel::(cx); - panel.update(cx, |panel, cx| panel.open_configuration(cx)); + workspace.focus_panel::(window, cx); + panel.update(cx, |panel, cx| panel.open_configuration(window, cx)); } }); }, @@ -89,22 +88,22 @@ enum ActiveView { } pub struct AssistantPanel { - workspace: WeakView, - project: Model, + workspace: WeakEntity, + project: Entity, fs: Arc, language_registry: Arc, - thread_store: Model, - thread: View, - message_editor: View, - context_store: Model, - context_editor: Option>, - context_history: Option>, - configuration: Option>, + thread_store: Entity, + thread: Entity, + message_editor: Entity, + context_store: Entity, + context_editor: Option>, + context_history: Option>, + configuration: Option>, configuration_subscription: Option, tools: Arc, local_timezone: UtcOffset, active_view: ActiveView, - history: View, + history: Entity, new_item_context_menu_handle: PopoverMenuHandle, open_history_context_menu_handle: PopoverMenuHandle, width: Option, @@ -113,10 +112,10 @@ pub struct AssistantPanel { impl AssistantPanel { pub fn load( - workspace: WeakView, + workspace: WeakEntity, prompt_builder: Arc, cx: AsyncWindowContext, - ) -> Task>> { + ) -> Task>> { cx.spawn(|mut cx| async move { let tools = Arc::new(ToolWorkingSet::default()); let thread_store = workspace @@ -140,32 +139,34 @@ impl AssistantPanel { })? .await?; - workspace.update(&mut cx, |workspace, cx| { - cx.new_view(|cx| Self::new(workspace, thread_store, context_store, tools, cx)) + workspace.update_in(&mut cx, |workspace, window, cx| { + cx.new(|cx| Self::new(workspace, thread_store, context_store, tools, window, cx)) }) }) } fn new( workspace: &Workspace, - thread_store: Model, - context_store: Model, + thread_store: Entity, + context_store: Entity, tools: Arc, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Self { let thread = thread_store.update(cx, |this, cx| this.create_thread(cx)); let fs = workspace.app_state().fs.clone(); let project = workspace.project().clone(); let language_registry = project.read(cx).languages().clone(); let workspace = workspace.weak_handle(); - let weak_self = cx.view().downgrade(); + let weak_self = cx.model().downgrade(); - let message_editor = cx.new_view(|cx| { + let message_editor = cx.new(|cx| { MessageEditor::new( fs.clone(), workspace.clone(), thread_store.downgrade(), thread.clone(), + window, cx, ) }); @@ -177,13 +178,14 @@ impl AssistantPanel { fs: fs.clone(), language_registry: language_registry.clone(), thread_store: thread_store.clone(), - thread: cx.new_view(|cx| { + thread: cx.new(|cx| { ActiveThread::new( thread.clone(), thread_store.clone(), workspace, language_registry, tools.clone(), + window, cx, ) }), @@ -198,7 +200,7 @@ impl AssistantPanel { chrono::Local::now().offset().local_minus_utc(), ) .unwrap(), - history: cx.new_view(|cx| ThreadHistory::new(weak_self, thread_store, cx)), + history: cx.new(|cx| ThreadHistory::new(weak_self, thread_store, cx)), new_item_context_menu_handle: PopoverMenuHandle::default(), open_history_context_menu_handle: PopoverMenuHandle::default(), width: None, @@ -209,58 +211,66 @@ impl AssistantPanel { pub fn toggle_focus( workspace: &mut Workspace, _: &ToggleFocus, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let settings = AssistantSettings::get_global(cx); if !settings.enabled { return; } - workspace.toggle_panel_focus::(cx); + workspace.toggle_panel_focus::(window, cx); } pub(crate) fn local_timezone(&self) -> UtcOffset { self.local_timezone } - pub(crate) fn thread_store(&self) -> &Model { + pub(crate) fn thread_store(&self) -> &Entity { &self.thread_store } - fn cancel(&mut self, _: &editor::actions::Cancel, cx: &mut ViewContext) { + fn cancel( + &mut self, + _: &editor::actions::Cancel, + _window: &mut Window, + cx: &mut Context, + ) { self.thread .update(cx, |thread, cx| thread.cancel_last_completion(cx)); } - fn new_thread(&mut self, cx: &mut ViewContext) { + fn new_thread(&mut self, window: &mut Window, cx: &mut Context) { let thread = self .thread_store .update(cx, |this, cx| this.create_thread(cx)); self.active_view = ActiveView::Thread; - self.thread = cx.new_view(|cx| { + self.thread = cx.new(|cx| { ActiveThread::new( thread.clone(), self.thread_store.clone(), self.workspace.clone(), self.language_registry.clone(), self.tools.clone(), + window, cx, ) }); - self.message_editor = cx.new_view(|cx| { + self.message_editor = cx.new(|cx| { MessageEditor::new( self.fs.clone(), self.workspace.clone(), self.thread_store.downgrade(), thread, + window, cx, ) }); - self.message_editor.focus_handle(cx).focus(cx); + self.message_editor.focus_handle(cx).focus(window); } - fn new_prompt_editor(&mut self, cx: &mut ViewContext) { + fn new_prompt_editor(&mut self, window: &mut Window, cx: &mut Context) { self.active_view = ActiveView::PromptEditor; let context = self @@ -270,25 +280,31 @@ impl AssistantPanel { .log_err() .flatten(); - self.context_editor = Some(cx.new_view(|cx| { + self.context_editor = Some(cx.new(|cx| { let mut editor = ContextEditor::for_context( context, self.fs.clone(), self.workspace.clone(), self.project.clone(), lsp_adapter_delegate, + window, cx, ); - editor.insert_default_prompt(cx); + editor.insert_default_prompt(window, cx); editor })); if let Some(context_editor) = self.context_editor.as_ref() { - context_editor.focus_handle(cx).focus(cx); + context_editor.focus_handle(cx).focus(window); } } - fn deploy_prompt_library(&mut self, _: &DeployPromptLibrary, cx: &mut ViewContext) { + fn deploy_prompt_library( + &mut self, + _: &DeployPromptLibrary, + _window: &mut Window, + cx: &mut Context, + ) { open_prompt_library( self.language_registry.clone(), Box::new(PromptLibraryInlineAssist::new(self.workspace.clone())), @@ -304,25 +320,26 @@ impl AssistantPanel { .detach_and_log_err(cx); } - fn open_history(&mut self, cx: &mut ViewContext) { + fn open_history(&mut self, window: &mut Window, cx: &mut Context) { self.active_view = ActiveView::History; - self.history.focus_handle(cx).focus(cx); + self.history.focus_handle(cx).focus(window); cx.notify(); } - fn open_prompt_editor_history(&mut self, cx: &mut ViewContext) { + fn open_prompt_editor_history(&mut self, window: &mut Window, cx: &mut Context) { self.active_view = ActiveView::PromptEditorHistory; - self.context_history = Some(cx.new_view(|cx| { + self.context_history = Some(cx.new(|cx| { ContextHistory::new( self.project.clone(), self.context_store.clone(), self.workspace.clone(), + window, cx, ) })); if let Some(context_history) = self.context_history.as_ref() { - context_history.focus_handle(cx).focus(cx); + context_history.focus_handle(cx).focus(window); } cx.notify(); @@ -331,7 +348,8 @@ impl AssistantPanel { fn open_saved_prompt_editor( &mut self, path: PathBuf, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { let context = self .context_store @@ -342,16 +360,17 @@ impl AssistantPanel { let lsp_adapter_delegate = make_lsp_adapter_delegate(&project, cx).log_err().flatten(); - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { let context = context.await?; - this.update(&mut cx, |this, cx| { - let editor = cx.new_view(|cx| { + this.update_in(&mut cx, |this, window, cx| { + let editor = cx.new(|cx| { ContextEditor::for_context( context, fs, workspace, project, lsp_adapter_delegate, + window, cx, ) }); @@ -367,57 +386,64 @@ impl AssistantPanel { pub(crate) fn open_thread( &mut self, thread_id: &ThreadId, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { let open_thread_task = self .thread_store .update(cx, |this, cx| this.open_thread(thread_id, cx)); - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { let thread = open_thread_task.await?; - this.update(&mut cx, |this, cx| { + this.update_in(&mut cx, |this, window, cx| { this.active_view = ActiveView::Thread; - this.thread = cx.new_view(|cx| { + this.thread = cx.new(|cx| { ActiveThread::new( thread.clone(), this.thread_store.clone(), this.workspace.clone(), this.language_registry.clone(), this.tools.clone(), + window, cx, ) }); - this.message_editor = cx.new_view(|cx| { + this.message_editor = cx.new(|cx| { MessageEditor::new( this.fs.clone(), this.workspace.clone(), this.thread_store.downgrade(), thread, + window, cx, ) }); - this.message_editor.focus_handle(cx).focus(cx); + this.message_editor.focus_handle(cx).focus(window); }) }) } - pub(crate) fn open_configuration(&mut self, cx: &mut ViewContext) { + pub(crate) fn open_configuration(&mut self, window: &mut Window, cx: &mut Context) { self.active_view = ActiveView::Configuration; - self.configuration = Some(cx.new_view(AssistantConfiguration::new)); + self.configuration = Some(cx.new(|cx| AssistantConfiguration::new(window, cx))); if let Some(configuration) = self.configuration.as_ref() { - self.configuration_subscription = - Some(cx.subscribe(configuration, Self::handle_assistant_configuration_event)); + self.configuration_subscription = Some(cx.subscribe_in( + configuration, + window, + Self::handle_assistant_configuration_event, + )); - configuration.focus_handle(cx).focus(cx); + configuration.focus_handle(cx).focus(window); } } fn handle_assistant_configuration_event( &mut self, - _view: View, + _model: &Entity, event: &AssistantConfigurationEvent, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { match event { AssistantConfigurationEvent::NewThread(provider) => { @@ -436,24 +462,24 @@ impl AssistantPanel { } } - self.new_thread(cx); + self.new_thread(window, cx); } } } - pub(crate) fn active_thread(&self, cx: &AppContext) -> Model { + pub(crate) fn active_thread(&self, cx: &App) -> Entity { self.thread.read(cx).thread().clone() } - pub(crate) fn delete_thread(&mut self, thread_id: &ThreadId, cx: &mut ViewContext) { + pub(crate) fn delete_thread(&mut self, thread_id: &ThreadId, cx: &mut Context) { self.thread_store .update(cx, |this, cx| this.delete_thread(thread_id, cx)) .detach_and_log_err(cx); } } -impl FocusableView for AssistantPanel { - fn focus_handle(&self, cx: &AppContext) -> FocusHandle { +impl Focusable for AssistantPanel { + fn focus_handle(&self, cx: &App) -> FocusHandle { match self.active_view { ActiveView::Thread => self.message_editor.focus_handle(cx), ActiveView::History => self.history.focus_handle(cx), @@ -489,7 +515,7 @@ impl Panel for AssistantPanel { "AssistantPanel2" } - fn position(&self, cx: &WindowContext) -> DockPosition { + fn position(&self, _window: &Window, cx: &App) -> DockPosition { match AssistantSettings::get_global(cx).dock { AssistantDockPosition::Left => DockPosition::Left, AssistantDockPosition::Bottom => DockPosition::Bottom, @@ -501,7 +527,7 @@ impl Panel for AssistantPanel { true } - fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext) { + fn set_position(&mut self, position: DockPosition, _: &mut Window, cx: &mut Context) { settings::update_settings_file::( self.fs.clone(), cx, @@ -516,9 +542,9 @@ impl Panel for AssistantPanel { ); } - fn size(&self, cx: &WindowContext) -> Pixels { + fn size(&self, window: &Window, cx: &App) -> Pixels { let settings = AssistantSettings::get_global(cx); - match self.position(cx) { + match self.position(window, cx) { DockPosition::Left | DockPosition::Right => { self.width.unwrap_or(settings.default_width) } @@ -526,21 +552,21 @@ impl Panel for AssistantPanel { } } - fn set_size(&mut self, size: Option, cx: &mut ViewContext) { - match self.position(cx) { + fn set_size(&mut self, size: Option, window: &mut Window, cx: &mut Context) { + match self.position(window, cx) { DockPosition::Left | DockPosition::Right => self.width = size, DockPosition::Bottom => self.height = size, } cx.notify(); } - fn set_active(&mut self, _active: bool, _cx: &mut ViewContext) {} + fn set_active(&mut self, _active: bool, _window: &mut Window, _cx: &mut Context) {} fn remote_id() -> Option { Some(proto::PanelId::AssistantPanel) } - fn icon(&self, cx: &WindowContext) -> Option { + fn icon(&self, _window: &Window, cx: &App) -> Option { let settings = AssistantSettings::get_global(cx); if !settings.enabled || !settings.button { return None; @@ -549,7 +575,7 @@ impl Panel for AssistantPanel { Some(IconName::ZedAssistant) } - fn icon_tooltip(&self, _cx: &WindowContext) -> Option<&'static str> { + fn icon_tooltip(&self, _window: &Window, _cx: &App) -> Option<&'static str> { Some("Assistant Panel") } @@ -563,7 +589,7 @@ impl Panel for AssistantPanel { } impl AssistantPanel { - fn render_toolbar(&self, cx: &mut ViewContext) -> impl IntoElement { + fn render_toolbar(&self, cx: &mut Context) -> impl IntoElement { let thread = self.thread.read(cx); let title = match self.active_view { @@ -612,12 +638,12 @@ impl AssistantPanel { IconButton::new("new", IconName::Plus) .icon_size(IconSize::Small) .style(ButtonStyle::Subtle) - .tooltip(|cx| Tooltip::text("New…", cx)), + .tooltip(Tooltip::text("New…")), ) .anchor(Corner::TopRight) .with_handle(self.new_item_context_menu_handle.clone()) - .menu(move |cx| { - Some(ContextMenu::build(cx, |menu, _| { + .menu(move |window, cx| { + Some(ContextMenu::build(window, cx, |menu, _window, _cx| { menu.action("New Thread", NewThread.boxed_clone()) .action("New Prompt Editor", NewPromptEditor.boxed_clone()) })) @@ -629,12 +655,12 @@ impl AssistantPanel { IconButton::new("open-history", IconName::HistoryRerun) .icon_size(IconSize::Small) .style(ButtonStyle::Subtle) - .tooltip(|cx| Tooltip::text("History…", cx)), + .tooltip(Tooltip::text("History…")), ) .anchor(Corner::TopRight) .with_handle(self.open_history_context_menu_handle.clone()) - .menu(move |cx| { - Some(ContextMenu::build(cx, |menu, _| { + .menu(move |window, cx| { + Some(ContextMenu::build(window, cx, |menu, _window, _cx| { menu.action("Thread History", OpenHistory.boxed_clone()) .action( "Prompt Editor History", @@ -647,23 +673,29 @@ impl AssistantPanel { IconButton::new("configure-assistant", IconName::Settings) .icon_size(IconSize::Small) .style(ButtonStyle::Subtle) - .tooltip(move |cx| Tooltip::text("Configure Assistant", cx)) - .on_click(move |_event, cx| { - cx.dispatch_action(OpenConfiguration.boxed_clone()); + .tooltip(Tooltip::text("Configure Assistant")) + .on_click(move |_event, _window, cx| { + cx.dispatch_action(&OpenConfiguration); }), ), ) } - fn render_active_thread_or_empty_state(&self, cx: &mut ViewContext) -> AnyElement { + fn render_active_thread_or_empty_state( + &self, + window: &mut Window, + cx: &mut Context, + ) -> AnyElement { if self.thread.read(cx).is_empty() { - return self.render_thread_empty_state(cx).into_any_element(); + return self + .render_thread_empty_state(window, cx) + .into_any_element(); } - self.thread.clone().into_any() + self.thread.clone().into_any_element() } - fn configuration_error(&self, cx: &AppContext) -> Option { + fn configuration_error(&self, cx: &App) -> Option { let Some(provider) = LanguageModelRegistry::read_global(cx).active_provider() else { return Some(ConfigurationError::NoProvider); }; @@ -679,7 +711,11 @@ impl AssistantPanel { None } - fn render_thread_empty_state(&self, cx: &mut ViewContext) -> impl IntoElement { + fn render_thread_empty_state( + &self, + window: &mut Window, + cx: &mut Context, + ) -> impl IntoElement { let recent_threads = self .thread_store .update(cx, |this, _cx| this.recent_threads(3)); @@ -729,8 +765,8 @@ impl AssistantPanel { .icon(Some(IconName::Sliders)) .icon_size(IconSize::Small) .icon_position(IconPosition::Start) - .on_click(cx.listener(|this, _, cx| { - this.open_configuration(cx); + .on_click(cx.listener(|this, _, window, cx| { + this.open_configuration(window, cx); })), ), ), @@ -775,7 +811,7 @@ impl AssistantPanel { .child(v_flex().mx_auto().w_4_5().gap_2().children( recent_threads.into_iter().map(|thread| { // TODO: keyboard navigation - PastThread::new(thread, cx.view().downgrade(), false) + PastThread::new(thread, cx.model().downgrade(), false) }), )) .child( @@ -786,17 +822,17 @@ impl AssistantPanel { .key_binding(KeyBinding::for_action_in( &OpenHistory, &self.focus_handle(cx), - cx, + window, )) - .on_click(move |_event, cx| { - cx.dispatch_action(OpenHistory.boxed_clone()); + .on_click(move |_event, window, cx| { + window.dispatch_action(OpenHistory.boxed_clone(), cx); }), ), ) }) } - fn render_last_error(&self, cx: &mut ViewContext) -> Option { + fn render_last_error(&self, cx: &mut Context) -> Option { let last_error = self.thread.read(cx).last_error()?; Some( @@ -822,7 +858,7 @@ impl AssistantPanel { ) } - fn render_payment_required_error(&self, cx: &mut ViewContext) -> AnyElement { + fn render_payment_required_error(&self, cx: &mut Context) -> AnyElement { const ERROR_MESSAGE: &str = "Free tier exceeded. Subscribe and add payment to continue using Zed LLMs. You'll be billed at cost for tokens used."; v_flex() @@ -846,7 +882,7 @@ impl AssistantPanel { .justify_end() .mt_1() .child(Button::new("subscribe", "Subscribe").on_click(cx.listener( - |this, _, cx| { + |this, _, _, cx| { this.thread.update(cx, |this, _cx| { this.clear_last_error(); }); @@ -856,7 +892,7 @@ impl AssistantPanel { }, ))) .child(Button::new("dismiss", "Dismiss").on_click(cx.listener( - |this, _, cx| { + |this, _, _, cx| { this.thread.update(cx, |this, _cx| { this.clear_last_error(); }); @@ -868,7 +904,7 @@ impl AssistantPanel { .into_any() } - fn render_max_monthly_spend_reached_error(&self, cx: &mut ViewContext) -> AnyElement { + fn render_max_monthly_spend_reached_error(&self, cx: &mut Context) -> AnyElement { const ERROR_MESSAGE: &str = "You have reached your maximum monthly spend. Increase your spend limit to continue using Zed LLMs."; v_flex() @@ -893,7 +929,7 @@ impl AssistantPanel { .mt_1() .child( Button::new("subscribe", "Update Monthly Spend Limit").on_click( - cx.listener(|this, _, cx| { + cx.listener(|this, _, _, cx| { this.thread.update(cx, |this, _cx| { this.clear_last_error(); }); @@ -904,7 +940,7 @@ impl AssistantPanel { ), ) .child(Button::new("dismiss", "Dismiss").on_click(cx.listener( - |this, _, cx| { + |this, _, _, cx| { this.thread.update(cx, |this, _cx| { this.clear_last_error(); }); @@ -919,7 +955,7 @@ impl AssistantPanel { fn render_error_message( &self, error_message: &SharedString, - cx: &mut ViewContext, + cx: &mut Context, ) -> AnyElement { v_flex() .gap_0p5() @@ -945,7 +981,7 @@ impl AssistantPanel { .justify_end() .mt_1() .child(Button::new("dismiss", "Dismiss").on_click(cx.listener( - |this, _, cx| { + |this, _, _, cx| { this.thread.update(cx, |this, _cx| { this.clear_last_error(); }); @@ -959,23 +995,23 @@ impl AssistantPanel { } impl Render for AssistantPanel { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { v_flex() .key_context("AssistantPanel2") .justify_between() .size_full() .on_action(cx.listener(Self::cancel)) - .on_action(cx.listener(|this, _: &NewThread, cx| { - this.new_thread(cx); + .on_action(cx.listener(|this, _: &NewThread, window, cx| { + this.new_thread(window, cx); })) - .on_action(cx.listener(|this, _: &OpenHistory, cx| { - this.open_history(cx); + .on_action(cx.listener(|this, _: &OpenHistory, window, cx| { + this.open_history(window, cx); })) .on_action(cx.listener(Self::deploy_prompt_library)) .child(self.render_toolbar(cx)) .map(|parent| match self.active_view { ActiveView::Thread => parent - .child(self.render_active_thread_or_empty_state(cx)) + .child(self.render_active_thread_or_empty_state(window, cx)) .child( h_flex() .border_t_1() @@ -992,11 +1028,11 @@ impl Render for AssistantPanel { } struct PromptLibraryInlineAssist { - workspace: WeakView, + workspace: WeakEntity, } impl PromptLibraryInlineAssist { - pub fn new(workspace: WeakView) -> Self { + pub fn new(workspace: WeakEntity) -> Self { Self { workspace } } } @@ -1004,21 +1040,25 @@ impl PromptLibraryInlineAssist { impl prompt_library::InlineAssistDelegate for PromptLibraryInlineAssist { fn assist( &self, - prompt_editor: &View, + prompt_editor: &Entity, _initial_prompt: Option, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { InlineAssistant::update_global(cx, |assistant, cx| { - assistant.assist(&prompt_editor, self.workspace.clone(), None, cx) + assistant.assist(&prompt_editor, self.workspace.clone(), None, window, cx) }) } fn focus_assistant_panel( &self, workspace: &mut Workspace, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> bool { - workspace.focus_panel::(cx).is_some() + workspace + .focus_panel::(window, cx) + .is_some() } } @@ -1028,8 +1068,9 @@ impl AssistantPanelDelegate for ConcreteAssistantPanelDelegate { fn active_context_editor( &self, workspace: &mut Workspace, - cx: &mut ViewContext, - ) -> Option> { + _window: &mut Window, + cx: &mut Context, + ) -> Option> { let panel = workspace.panel::(cx)?; panel.update(cx, |panel, _cx| panel.context_editor.clone()) } @@ -1038,21 +1079,25 @@ impl AssistantPanelDelegate for ConcreteAssistantPanelDelegate { &self, workspace: &mut Workspace, path: std::path::PathBuf, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { let Some(panel) = workspace.panel::(cx) else { return Task::ready(Err(anyhow!("Assistant panel not found"))); }; - panel.update(cx, |panel, cx| panel.open_saved_prompt_editor(path, cx)) + panel.update(cx, |panel, cx| { + panel.open_saved_prompt_editor(path, window, cx) + }) } fn open_remote_context( &self, _workspace: &mut Workspace, _context_id: assistant_context_editor::ContextId, - _cx: &mut ViewContext, - ) -> Task>> { + _window: &mut Window, + _cx: &mut Context, + ) -> Task>> { Task::ready(Err(anyhow!("opening remote context not implemented"))) } @@ -1060,7 +1105,8 @@ impl AssistantPanelDelegate for ConcreteAssistantPanelDelegate { &self, _workspace: &mut Workspace, _creases: Vec<(String, String)>, - _cx: &mut ViewContext, + _window: &mut Window, + _cx: &mut Context, ) { } } diff --git a/crates/assistant2/src/buffer_codegen.rs b/crates/assistant2/src/buffer_codegen.rs index 09850ea5f7..6c3e67f8de 100644 --- a/crates/assistant2/src/buffer_codegen.rs +++ b/crates/assistant2/src/buffer_codegen.rs @@ -6,7 +6,7 @@ use client::telemetry::Telemetry; use collections::HashSet; use editor::{Anchor, AnchorRangeExt, MultiBuffer, MultiBufferSnapshot, ToOffset as _, ToPoint}; use futures::{channel::mpsc, future::LocalBoxFuture, join, SinkExt, Stream, StreamExt}; -use gpui::{AppContext, Context as _, EventEmitter, Model, ModelContext, Subscription, Task}; +use gpui::{App, AppContext as _, Context, Entity, EventEmitter, Subscription, Task}; use language::{Buffer, IndentKind, Point, TransactionId}; use language_model::{ LanguageModel, LanguageModelRegistry, LanguageModelRequest, LanguageModelRequestMessage, @@ -32,14 +32,14 @@ use streaming_diff::{CharOperation, LineDiff, LineOperation, StreamingDiff}; use telemetry_events::{AssistantEvent, AssistantKind, AssistantPhase}; pub struct BufferCodegen { - alternatives: Vec>, + alternatives: Vec>, pub active_alternative: usize, seen_alternatives: HashSet, subscriptions: Vec, - buffer: Model, + buffer: Entity, range: Range, initial_transaction_id: Option, - context_store: Model, + context_store: Entity, telemetry: Arc, builder: Arc, pub is_insertion: bool, @@ -47,15 +47,15 @@ pub struct BufferCodegen { impl BufferCodegen { pub fn new( - buffer: Model, + buffer: Entity, range: Range, initial_transaction_id: Option, - context_store: Model, + context_store: Entity, telemetry: Arc, builder: Arc, - cx: &mut ModelContext, + cx: &mut Context, ) -> Self { - let codegen = cx.new_model(|cx| { + let codegen = cx.new(|cx| { CodegenAlternative::new( buffer.clone(), range.clone(), @@ -83,7 +83,7 @@ impl BufferCodegen { this } - fn subscribe_to_alternative(&mut self, cx: &mut ModelContext) { + fn subscribe_to_alternative(&mut self, cx: &mut Context) { let codegen = self.active_alternative().clone(); self.subscriptions.clear(); self.subscriptions @@ -92,22 +92,22 @@ impl BufferCodegen { .push(cx.subscribe(&codegen, |_, _, event, cx| cx.emit(*event))); } - pub fn active_alternative(&self) -> &Model { + pub fn active_alternative(&self) -> &Entity { &self.alternatives[self.active_alternative] } - pub fn status<'a>(&self, cx: &'a AppContext) -> &'a CodegenStatus { + pub fn status<'a>(&self, cx: &'a App) -> &'a CodegenStatus { &self.active_alternative().read(cx).status } - pub fn alternative_count(&self, cx: &AppContext) -> usize { + pub fn alternative_count(&self, cx: &App) -> usize { LanguageModelRegistry::read_global(cx) .inline_alternative_models() .len() + 1 } - pub fn cycle_prev(&mut self, cx: &mut ModelContext) { + pub fn cycle_prev(&mut self, cx: &mut Context) { let next_active_ix = if self.active_alternative == 0 { self.alternatives.len() - 1 } else { @@ -116,12 +116,12 @@ impl BufferCodegen { self.activate(next_active_ix, cx); } - pub fn cycle_next(&mut self, cx: &mut ModelContext) { + pub fn cycle_next(&mut self, cx: &mut Context) { let next_active_ix = (self.active_alternative + 1) % self.alternatives.len(); self.activate(next_active_ix, cx); } - fn activate(&mut self, index: usize, cx: &mut ModelContext) { + fn activate(&mut self, index: usize, cx: &mut Context) { self.active_alternative() .update(cx, |codegen, cx| codegen.set_active(false, cx)); self.seen_alternatives.insert(index); @@ -132,7 +132,7 @@ impl BufferCodegen { cx.notify(); } - pub fn start(&mut self, user_prompt: String, cx: &mut ModelContext) -> Result<()> { + pub fn start(&mut self, user_prompt: String, cx: &mut Context) -> Result<()> { let alternative_models = LanguageModelRegistry::read_global(cx) .inline_alternative_models() .to_vec(); @@ -143,7 +143,7 @@ impl BufferCodegen { self.alternatives.truncate(1); for _ in 0..alternative_models.len() { - self.alternatives.push(cx.new_model(|cx| { + self.alternatives.push(cx.new(|cx| { CodegenAlternative::new( self.buffer.clone(), self.range.clone(), @@ -172,13 +172,13 @@ impl BufferCodegen { Ok(()) } - pub fn stop(&mut self, cx: &mut ModelContext) { + pub fn stop(&mut self, cx: &mut Context) { for codegen in &self.alternatives { codegen.update(cx, |codegen, cx| codegen.stop(cx)); } } - pub fn undo(&mut self, cx: &mut ModelContext) { + pub fn undo(&mut self, cx: &mut Context) { self.active_alternative() .update(cx, |codegen, cx| codegen.undo(cx)); @@ -190,27 +190,27 @@ impl BufferCodegen { }); } - pub fn buffer(&self, cx: &AppContext) -> Model { + pub fn buffer(&self, cx: &App) -> Entity { self.active_alternative().read(cx).buffer.clone() } - pub fn old_buffer(&self, cx: &AppContext) -> Model { + pub fn old_buffer(&self, cx: &App) -> Entity { self.active_alternative().read(cx).old_buffer.clone() } - pub fn snapshot(&self, cx: &AppContext) -> MultiBufferSnapshot { + pub fn snapshot(&self, cx: &App) -> MultiBufferSnapshot { self.active_alternative().read(cx).snapshot.clone() } - pub fn edit_position(&self, cx: &AppContext) -> Option { + pub fn edit_position(&self, cx: &App) -> Option { self.active_alternative().read(cx).edit_position } - pub fn diff<'a>(&self, cx: &'a AppContext) -> &'a Diff { + pub fn diff<'a>(&self, cx: &'a App) -> &'a Diff { &self.active_alternative().read(cx).diff } - pub fn last_equal_ranges<'a>(&self, cx: &'a AppContext) -> &'a [Range] { + pub fn last_equal_ranges<'a>(&self, cx: &'a App) -> &'a [Range] { self.active_alternative().read(cx).last_equal_ranges() } } @@ -218,8 +218,8 @@ impl BufferCodegen { impl EventEmitter for BufferCodegen {} pub struct CodegenAlternative { - buffer: Model, - old_buffer: Model, + buffer: Entity, + old_buffer: Entity, snapshot: MultiBufferSnapshot, edit_position: Option, range: Range, @@ -228,7 +228,7 @@ pub struct CodegenAlternative { status: CodegenStatus, generation: Task<()>, diff: Diff, - context_store: Option>, + context_store: Option>, telemetry: Option>, _subscription: gpui::Subscription, builder: Arc, @@ -245,13 +245,13 @@ impl EventEmitter for CodegenAlternative {} impl CodegenAlternative { pub fn new( - buffer: Model, + buffer: Entity, range: Range, active: bool, - context_store: Option>, + context_store: Option>, telemetry: Option>, builder: Arc, - cx: &mut ModelContext, + cx: &mut Context, ) -> Self { let snapshot = buffer.read(cx).snapshot(cx); @@ -259,7 +259,7 @@ impl CodegenAlternative { .range_to_buffer_ranges(range.clone()) .pop() .unwrap(); - let old_buffer = cx.new_model(|cx| { + let old_buffer = cx.new(|cx| { let text = old_buffer.as_rope().clone(); let line_ending = old_buffer.line_ending(); let language = old_buffer.language().cloned(); @@ -303,7 +303,7 @@ impl CodegenAlternative { } } - pub fn set_active(&mut self, active: bool, cx: &mut ModelContext) { + pub fn set_active(&mut self, active: bool, cx: &mut Context) { if active != self.active { self.active = active; @@ -327,9 +327,9 @@ impl CodegenAlternative { fn handle_buffer_event( &mut self, - _buffer: Model, + _buffer: Entity, event: &multi_buffer::Event, - cx: &mut ModelContext, + cx: &mut Context, ) { if let multi_buffer::Event::TransactionUndone { transaction_id } = event { if self.transformation_transaction_id == Some(*transaction_id) { @@ -348,7 +348,7 @@ impl CodegenAlternative { &mut self, user_prompt: String, model: Arc, - cx: &mut ModelContext, + cx: &mut Context, ) -> Result<()> { if let Some(transformation_transaction_id) = self.transformation_transaction_id.take() { self.buffer.update(cx, |buffer, cx| { @@ -375,11 +375,7 @@ impl CodegenAlternative { Ok(()) } - fn build_request( - &self, - user_prompt: String, - cx: &mut AppContext, - ) -> Result { + fn build_request(&self, user_prompt: String, cx: &mut App) -> Result { let buffer = self.buffer.read(cx).snapshot(cx); let language = buffer.language_at(self.range.start); let language_name = if let Some(language) = language.as_ref() { @@ -438,7 +434,7 @@ impl CodegenAlternative { model_provider_id: String, model_api_key: Option, stream: impl 'static + Future>, - cx: &mut ModelContext, + cx: &mut Context, ) { let start_time = Instant::now(); let snapshot = self.snapshot.clone(); @@ -696,7 +692,7 @@ impl CodegenAlternative { cx.notify(); } - pub fn stop(&mut self, cx: &mut ModelContext) { + pub fn stop(&mut self, cx: &mut Context) { self.last_equal_ranges.clear(); if self.diff.is_empty() { self.status = CodegenStatus::Idle; @@ -708,7 +704,7 @@ impl CodegenAlternative { cx.notify(); } - pub fn undo(&mut self, cx: &mut ModelContext) { + pub fn undo(&mut self, cx: &mut Context) { self.buffer.update(cx, |buffer, cx| { if let Some(transaction_id) = self.transformation_transaction_id.take() { buffer.undo_transaction(transaction_id, cx); @@ -720,7 +716,7 @@ impl CodegenAlternative { fn apply_edits( &mut self, edits: impl IntoIterator, String)>, - cx: &mut ModelContext, + cx: &mut Context, ) { let transaction = self.buffer.update(cx, |buffer, cx| { // Avoid grouping assistant edits with user edits. @@ -747,7 +743,7 @@ impl CodegenAlternative { fn reapply_line_based_diff( &mut self, line_operations: impl IntoIterator, - cx: &mut ModelContext, + cx: &mut Context, ) { let old_snapshot = self.snapshot.clone(); let old_range = self.range.to_point(&old_snapshot); @@ -803,7 +799,7 @@ impl CodegenAlternative { } } - fn reapply_batch_diff(&mut self, cx: &mut ModelContext) -> Task<()> { + fn reapply_batch_diff(&mut self, cx: &mut Context) -> Task<()> { let old_snapshot = self.snapshot.clone(); let old_range = self.range.to_point(&old_snapshot); let new_snapshot = self.buffer.read(cx).snapshot(cx); @@ -1081,15 +1077,14 @@ mod tests { } } "}; - let buffer = - cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); let range = buffer.read_with(cx, |buffer, cx| { let snapshot = buffer.snapshot(cx); snapshot.anchor_before(Point::new(1, 0))..snapshot.anchor_after(Point::new(4, 5)) }); let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); - let codegen = cx.new_model(|cx| { + let codegen = cx.new(|cx| { CodegenAlternative::new( buffer.clone(), range.clone(), @@ -1146,15 +1141,14 @@ mod tests { le } "}; - let buffer = - cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); let range = buffer.read_with(cx, |buffer, cx| { let snapshot = buffer.snapshot(cx); snapshot.anchor_before(Point::new(1, 6))..snapshot.anchor_after(Point::new(1, 6)) }); let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); - let codegen = cx.new_model(|cx| { + let codegen = cx.new(|cx| { CodegenAlternative::new( buffer.clone(), range.clone(), @@ -1214,15 +1208,14 @@ mod tests { " \n", "}\n" // ); - let buffer = - cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); let range = buffer.read_with(cx, |buffer, cx| { let snapshot = buffer.snapshot(cx); snapshot.anchor_before(Point::new(1, 2))..snapshot.anchor_after(Point::new(1, 2)) }); let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); - let codegen = cx.new_model(|cx| { + let codegen = cx.new(|cx| { CodegenAlternative::new( buffer.clone(), range.clone(), @@ -1282,14 +1275,14 @@ mod tests { \t} } "}; - let buffer = cx.new_model(|cx| Buffer::local(text, cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); let range = buffer.read_with(cx, |buffer, cx| { let snapshot = buffer.snapshot(cx); snapshot.anchor_before(Point::new(0, 0))..snapshot.anchor_after(Point::new(4, 2)) }); let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); - let codegen = cx.new_model(|cx| { + let codegen = cx.new(|cx| { CodegenAlternative::new( buffer.clone(), range.clone(), @@ -1337,15 +1330,14 @@ mod tests { let x = 0; } "}; - let buffer = - cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); let range = buffer.read_with(cx, |buffer, cx| { let snapshot = buffer.snapshot(cx); snapshot.anchor_before(Point::new(1, 0))..snapshot.anchor_after(Point::new(1, 14)) }); let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); - let codegen = cx.new_model(|cx| { + let codegen = cx.new(|cx| { CodegenAlternative::new( buffer.clone(), range.clone(), @@ -1432,7 +1424,7 @@ mod tests { } fn simulate_response_stream( - codegen: Model, + codegen: Entity, cx: &mut TestAppContext, ) -> mpsc::UnboundedSender { let (chunks_tx, chunks_rx) = mpsc::unbounded(); diff --git a/crates/assistant2/src/context.rs b/crates/assistant2/src/context.rs index 09462d246a..091cac0ddd 100644 --- a/crates/assistant2/src/context.rs +++ b/crates/assistant2/src/context.rs @@ -2,7 +2,7 @@ use std::path::Path; use std::rc::Rc; use file_icons::FileIcons; -use gpui::{AppContext, Model, SharedString}; +use gpui::{App, Entity, SharedString}; use language::Buffer; use language_model::{LanguageModelRequestMessage, MessageContent}; use serde::{Deserialize, Serialize}; @@ -63,14 +63,14 @@ impl ContextKind { } #[derive(Debug)] -pub enum Context { +pub enum AssistantContext { File(FileContext), Directory(DirectoryContext), FetchedUrl(FetchedUrlContext), Thread(ThreadContext), } -impl Context { +impl AssistantContext { pub fn id(&self) -> ContextId { match self { Self::File(file) => file.id, @@ -107,7 +107,7 @@ pub struct FetchedUrlContext { #[derive(Debug)] pub struct ThreadContext { pub id: ContextId, - pub thread: Model, + pub thread: Entity, pub text: SharedString, } @@ -117,13 +117,13 @@ pub struct ThreadContext { #[derive(Debug, Clone)] pub struct ContextBuffer { pub id: BufferId, - pub buffer: Model, + pub buffer: Entity, pub version: clock::Global, pub text: SharedString, } -impl Context { - pub fn snapshot(&self, cx: &AppContext) -> Option { +impl AssistantContext { + pub fn snapshot(&self, cx: &App) -> Option { match &self { Self::File(file_context) => file_context.snapshot(cx), Self::Directory(directory_context) => Some(directory_context.snapshot()), @@ -134,7 +134,7 @@ impl Context { } impl FileContext { - pub fn snapshot(&self, cx: &AppContext) -> Option { + pub fn snapshot(&self, cx: &App) -> Option { let buffer = self.context_buffer.buffer.read(cx); let path = buffer_path_log_err(buffer)?; let full_path: SharedString = path.to_string_lossy().into_owned().into(); @@ -221,7 +221,7 @@ impl FetchedUrlContext { } impl ThreadContext { - pub fn snapshot(&self, cx: &AppContext) -> ContextSnapshot { + pub fn snapshot(&self, cx: &App) -> ContextSnapshot { let thread = self.thread.read(cx); ContextSnapshot { id: self.id, diff --git a/crates/assistant2/src/context_picker.rs b/crates/assistant2/src/context_picker.rs index 4577db0bb8..51f23edc2f 100644 --- a/crates/assistant2/src/context_picker.rs +++ b/crates/assistant2/src/context_picker.rs @@ -9,10 +9,7 @@ use std::sync::Arc; use anyhow::{anyhow, Result}; use editor::Editor; use file_context_picker::render_file_context_entry; -use gpui::{ - AppContext, DismissEvent, EventEmitter, FocusHandle, FocusableView, Task, View, WeakModel, - WeakView, -}; +use gpui::{App, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, Task, WeakEntity}; use project::ProjectPath; use thread_context_picker::{render_thread_context_entry, ThreadContextEntry}; use ui::{prelude::*, ContextMenu, ContextMenuEntry, ContextMenuItem}; @@ -35,33 +32,38 @@ pub enum ConfirmBehavior { #[derive(Debug, Clone)] enum ContextPickerMode { - Default(View), - File(View), - Directory(View), - Fetch(View), - Thread(View), + Default(Entity), + File(Entity), + Directory(Entity), + Fetch(Entity), + Thread(Entity), } pub(super) struct ContextPicker { mode: ContextPickerMode, - workspace: WeakView, - editor: WeakView, - context_store: WeakModel, - thread_store: Option>, + workspace: WeakEntity, + editor: WeakEntity, + context_store: WeakEntity, + thread_store: Option>, confirm_behavior: ConfirmBehavior, } impl ContextPicker { pub fn new( - workspace: WeakView, - thread_store: Option>, - context_store: WeakModel, - editor: WeakView, + workspace: WeakEntity, + thread_store: Option>, + context_store: WeakEntity, + editor: WeakEntity, confirm_behavior: ConfirmBehavior, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Self { ContextPicker { - mode: ContextPickerMode::Default(ContextMenu::build(cx, |menu, _cx| menu)), + mode: ContextPickerMode::Default(ContextMenu::build( + window, + cx, + |menu, _window, _cx| menu, + )), workspace, context_store, thread_store, @@ -70,15 +72,15 @@ impl ContextPicker { } } - pub fn init(&mut self, cx: &mut ViewContext) { - self.mode = ContextPickerMode::Default(self.build_menu(cx)); + pub fn init(&mut self, window: &mut Window, cx: &mut Context) { + self.mode = ContextPickerMode::Default(self.build_menu(window, cx)); cx.notify(); } - fn build_menu(&mut self, cx: &mut ViewContext) -> View { - let context_picker = cx.view().clone(); + fn build_menu(&mut self, window: &mut Window, cx: &mut Context) -> Entity { + let context_picker = cx.model().clone(); - let menu = ContextMenu::build(cx, move |menu, cx| { + let menu = ContextMenu::build(window, cx, move |menu, _window, cx| { let recent = self.recent_entries(cx); let has_recent = !recent.is_empty(); let recent_entries = recent @@ -97,7 +99,7 @@ impl ContextPicker { let menu = menu .when(has_recent, |menu| { - menu.custom_row(|_| { + menu.custom_row(|_, _| { div() .mb_1() .child( @@ -117,8 +119,8 @@ impl ContextPicker { .icon(kind.icon()) .icon_size(IconSize::XSmall) .icon_color(Color::Muted) - .handler(move |cx| { - context_picker.update(cx, |this, cx| this.select_kind(kind, cx)) + .handler(move |window, cx| { + context_picker.update(cx, |this, cx| this.select_kind(kind, window, cx)) }) })); @@ -141,52 +143,56 @@ impl ContextPicker { self.thread_store.is_some() } - fn select_kind(&mut self, kind: ContextKind, cx: &mut ViewContext) { - let context_picker = cx.view().downgrade(); + fn select_kind(&mut self, kind: ContextKind, window: &mut Window, cx: &mut Context) { + let context_picker = cx.model().downgrade(); match kind { ContextKind::File => { - self.mode = ContextPickerMode::File(cx.new_view(|cx| { + self.mode = ContextPickerMode::File(cx.new(|cx| { FileContextPicker::new( context_picker.clone(), self.workspace.clone(), self.editor.clone(), self.context_store.clone(), self.confirm_behavior, + window, cx, ) })); } ContextKind::Directory => { - self.mode = ContextPickerMode::Directory(cx.new_view(|cx| { + self.mode = ContextPickerMode::Directory(cx.new(|cx| { DirectoryContextPicker::new( context_picker.clone(), self.workspace.clone(), self.context_store.clone(), self.confirm_behavior, + window, cx, ) })); } ContextKind::FetchedUrl => { - self.mode = ContextPickerMode::Fetch(cx.new_view(|cx| { + self.mode = ContextPickerMode::Fetch(cx.new(|cx| { FetchContextPicker::new( context_picker.clone(), self.workspace.clone(), self.context_store.clone(), self.confirm_behavior, + window, cx, ) })); } ContextKind::Thread => { if let Some(thread_store) = self.thread_store.as_ref() { - self.mode = ContextPickerMode::Thread(cx.new_view(|cx| { + self.mode = ContextPickerMode::Thread(cx.new(|cx| { ThreadContextPicker::new( thread_store.clone(), context_picker.clone(), self.context_store.clone(), self.confirm_behavior, + window, cx, ) })); @@ -195,12 +201,12 @@ impl ContextPicker { } cx.notify(); - cx.focus_self(); + cx.focus_self(window); } fn recent_menu_item( &self, - context_picker: View, + context_picker: Entity, ix: usize, entry: RecentEntry, ) -> ContextMenuItem { @@ -213,7 +219,7 @@ impl ContextPicker { let path = project_path.path.clone(); ContextMenuItem::custom_entry( - move |cx| { + move |_window, cx| { render_file_context_entry( ElementId::NamedInteger("ctx-recent".into(), ix), &path, @@ -223,9 +229,9 @@ impl ContextPicker { ) .into_any() }, - move |cx| { + move |window, cx| { context_picker.update(cx, |this, cx| { - this.add_recent_file(project_path.clone(), cx); + this.add_recent_file(project_path.clone(), window, cx); }) }, ) @@ -235,11 +241,11 @@ impl ContextPicker { let view_thread = thread.clone(); ContextMenuItem::custom_entry( - move |cx| { + move |_window, cx| { render_thread_context_entry(&view_thread, context_store.clone(), cx) .into_any() }, - move |cx| { + move |_window, cx| { context_picker.update(cx, |this, cx| { this.add_recent_thread(thread.clone(), cx) .detach_and_log_err(cx); @@ -250,7 +256,12 @@ impl ContextPicker { } } - fn add_recent_file(&self, project_path: ProjectPath, cx: &mut ViewContext) { + fn add_recent_file( + &self, + project_path: ProjectPath, + window: &mut Window, + cx: &mut Context, + ) { let Some(context_store) = self.context_store.upgrade() else { return; }; @@ -259,8 +270,10 @@ impl ContextPicker { context_store.add_file_from_path(project_path.clone(), cx) }); - cx.spawn(|_, mut cx| async move { task.await.notify_async_err(&mut cx) }) - .detach(); + cx.spawn_in(window, |_, mut cx| async move { + task.await.notify_async_err(&mut cx) + }) + .detach(); cx.notify(); } @@ -268,7 +281,7 @@ impl ContextPicker { fn add_recent_thread( &self, thread: ThreadContextEntry, - cx: &mut ViewContext, + cx: &mut Context, ) -> Task> { let Some(context_store) = self.context_store.upgrade() else { return Task::ready(Err(anyhow!("context store not available"))); @@ -293,7 +306,7 @@ impl ContextPicker { }) } - fn recent_entries(&self, cx: &mut WindowContext) -> Vec { + fn recent_entries(&self, cx: &mut App) -> Vec { let Some(workspace) = self.workspace.upgrade().map(|w| w.read(cx)) else { return vec![]; }; @@ -363,7 +376,7 @@ impl ContextPicker { recent } - fn active_singleton_buffer_path(workspace: &Workspace, cx: &AppContext) -> Option { + fn active_singleton_buffer_path(workspace: &Workspace, cx: &App) -> Option { let active_item = workspace.active_item(cx)?; let editor = active_item.to_any().downcast::().ok()?.read(cx); @@ -376,8 +389,8 @@ impl ContextPicker { impl EventEmitter for ContextPicker {} -impl FocusableView for ContextPicker { - fn focus_handle(&self, cx: &AppContext) -> FocusHandle { +impl Focusable for ContextPicker { + fn focus_handle(&self, cx: &App) -> FocusHandle { match &self.mode { ContextPickerMode::Default(menu) => menu.focus_handle(cx), ContextPickerMode::File(file_picker) => file_picker.focus_handle(cx), @@ -389,7 +402,7 @@ impl FocusableView for ContextPicker { } impl Render for ContextPicker { - fn render(&mut self, _cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { v_flex() .w(px(400.)) .min_w(px(400.)) diff --git a/crates/assistant2/src/context_picker/directory_context_picker.rs b/crates/assistant2/src/context_picker/directory_context_picker.rs index f434e114d2..0b5b545228 100644 --- a/crates/assistant2/src/context_picker/directory_context_picker.rs +++ b/crates/assistant2/src/context_picker/directory_context_picker.rs @@ -3,7 +3,7 @@ use std::sync::atomic::AtomicBool; use std::sync::Arc; use fuzzy::PathMatch; -use gpui::{AppContext, DismissEvent, FocusHandle, FocusableView, Task, View, WeakModel, WeakView}; +use gpui::{App, DismissEvent, Entity, FocusHandle, Focusable, Task, WeakEntity}; use picker::{Picker, PickerDelegate}; use project::{PathMatchCandidateSet, ProjectPath, WorktreeId}; use ui::{prelude::*, ListItem}; @@ -14,16 +14,17 @@ use crate::context_picker::{ConfirmBehavior, ContextPicker}; use crate::context_store::ContextStore; pub struct DirectoryContextPicker { - picker: View>, + picker: Entity>, } impl DirectoryContextPicker { pub fn new( - context_picker: WeakView, - workspace: WeakView, - context_store: WeakModel, + context_picker: WeakEntity, + workspace: WeakEntity, + context_store: WeakEntity, confirm_behavior: ConfirmBehavior, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Self { let delegate = DirectoryContextPickerDelegate::new( context_picker, @@ -31,28 +32,28 @@ impl DirectoryContextPicker { context_store, confirm_behavior, ); - let picker = cx.new_view(|cx| Picker::uniform_list(delegate, cx)); + let picker = cx.new(|cx| Picker::uniform_list(delegate, window, cx)); Self { picker } } } -impl FocusableView for DirectoryContextPicker { - fn focus_handle(&self, cx: &AppContext) -> FocusHandle { +impl Focusable for DirectoryContextPicker { + fn focus_handle(&self, cx: &App) -> FocusHandle { self.picker.focus_handle(cx) } } impl Render for DirectoryContextPicker { - fn render(&mut self, _cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { self.picker.clone() } } pub struct DirectoryContextPickerDelegate { - context_picker: WeakView, - workspace: WeakView, - context_store: WeakModel, + context_picker: WeakEntity, + workspace: WeakEntity, + context_store: WeakEntity, confirm_behavior: ConfirmBehavior, matches: Vec, selected_index: usize, @@ -60,9 +61,9 @@ pub struct DirectoryContextPickerDelegate { impl DirectoryContextPickerDelegate { pub fn new( - context_picker: WeakView, - workspace: WeakView, - context_store: WeakModel, + context_picker: WeakEntity, + workspace: WeakEntity, + context_store: WeakEntity, confirm_behavior: ConfirmBehavior, ) -> Self { Self { @@ -79,8 +80,8 @@ impl DirectoryContextPickerDelegate { &mut self, query: String, cancellation_flag: Arc, - workspace: &View, - cx: &mut ViewContext>, + workspace: &Entity, + cx: &mut Context>, ) -> Task> { if query.is_empty() { let workspace = workspace.read(cx); @@ -146,15 +147,25 @@ impl PickerDelegate for DirectoryContextPickerDelegate { self.selected_index } - fn set_selected_index(&mut self, ix: usize, _cx: &mut ViewContext>) { + fn set_selected_index( + &mut self, + ix: usize, + _window: &mut Window, + _cx: &mut Context>, + ) { self.selected_index = ix; } - fn placeholder_text(&self, _cx: &mut WindowContext) -> Arc { + fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc { "Search folders…".into() } - fn update_matches(&mut self, query: String, cx: &mut ViewContext>) -> Task<()> { + fn update_matches( + &mut self, + query: String, + _window: &mut Window, + cx: &mut Context>, + ) -> Task<()> { let Some(workspace) = self.workspace.upgrade() else { return Task::ready(()); }; @@ -173,7 +184,7 @@ impl PickerDelegate for DirectoryContextPickerDelegate { }) } - fn confirm(&mut self, _secondary: bool, cx: &mut ViewContext>) { + fn confirm(&mut self, _secondary: bool, window: &mut Window, cx: &mut Context>) { let Some(mat) = self.matches.get(self.selected_index) else { return; }; @@ -194,19 +205,19 @@ impl PickerDelegate for DirectoryContextPickerDelegate { }; let confirm_behavior = self.confirm_behavior; - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { match task.await.notify_async_err(&mut cx) { None => anyhow::Ok(()), - Some(()) => this.update(&mut cx, |this, cx| match confirm_behavior { + Some(()) => this.update_in(&mut cx, |this, window, cx| match confirm_behavior { ConfirmBehavior::KeepOpen => {} - ConfirmBehavior::Close => this.delegate.dismissed(cx), + ConfirmBehavior::Close => this.delegate.dismissed(window, cx), }), } }) .detach_and_log_err(cx); } - fn dismissed(&mut self, cx: &mut ViewContext>) { + fn dismissed(&mut self, _window: &mut Window, cx: &mut Context>) { self.context_picker .update(cx, |_, cx| { cx.emit(DismissEvent); @@ -218,7 +229,8 @@ impl PickerDelegate for DirectoryContextPickerDelegate { &self, ix: usize, selected: bool, - cx: &mut ViewContext>, + _window: &mut Window, + cx: &mut Context>, ) -> Option { let path_match = &self.matches[ix]; let directory_name = path_match.path.to_string_lossy().to_string(); diff --git a/crates/assistant2/src/context_picker/fetch_context_picker.rs b/crates/assistant2/src/context_picker/fetch_context_picker.rs index 7bb089e82b..c16beeea7a 100644 --- a/crates/assistant2/src/context_picker/fetch_context_picker.rs +++ b/crates/assistant2/src/context_picker/fetch_context_picker.rs @@ -4,27 +4,28 @@ use std::sync::Arc; use anyhow::{bail, Context as _, Result}; use futures::AsyncReadExt as _; -use gpui::{AppContext, DismissEvent, FocusHandle, FocusableView, Task, View, WeakModel, WeakView}; +use gpui::{App, DismissEvent, Entity, FocusHandle, Focusable, Task, WeakEntity}; use html_to_markdown::{convert_html_to_markdown, markdown, TagHandler}; use http_client::{AsyncBody, HttpClientWithUrl}; use picker::{Picker, PickerDelegate}; -use ui::{prelude::*, ListItem, ViewContext}; +use ui::{prelude::*, Context, ListItem, Window}; use workspace::Workspace; use crate::context_picker::{ConfirmBehavior, ContextPicker}; use crate::context_store::ContextStore; pub struct FetchContextPicker { - picker: View>, + picker: Entity>, } impl FetchContextPicker { pub fn new( - context_picker: WeakView, - workspace: WeakView, - context_store: WeakModel, + context_picker: WeakEntity, + workspace: WeakEntity, + context_store: WeakEntity, confirm_behavior: ConfirmBehavior, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Self { let delegate = FetchContextPickerDelegate::new( context_picker, @@ -32,20 +33,20 @@ impl FetchContextPicker { context_store, confirm_behavior, ); - let picker = cx.new_view(|cx| Picker::uniform_list(delegate, cx)); + let picker = cx.new(|cx| Picker::uniform_list(delegate, window, cx)); Self { picker } } } -impl FocusableView for FetchContextPicker { - fn focus_handle(&self, cx: &AppContext) -> FocusHandle { +impl Focusable for FetchContextPicker { + fn focus_handle(&self, cx: &App) -> FocusHandle { self.picker.focus_handle(cx) } } impl Render for FetchContextPicker { - fn render(&mut self, _cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { self.picker.clone() } } @@ -58,18 +59,18 @@ enum ContentType { } pub struct FetchContextPickerDelegate { - context_picker: WeakView, - workspace: WeakView, - context_store: WeakModel, + context_picker: WeakEntity, + workspace: WeakEntity, + context_store: WeakEntity, confirm_behavior: ConfirmBehavior, url: String, } impl FetchContextPickerDelegate { pub fn new( - context_picker: WeakView, - workspace: WeakView, - context_store: WeakModel, + context_picker: WeakEntity, + workspace: WeakEntity, + context_store: WeakEntity, confirm_behavior: ConfirmBehavior, ) -> Self { FetchContextPickerDelegate { @@ -166,7 +167,7 @@ impl PickerDelegate for FetchContextPickerDelegate { } } - fn no_matches_text(&self, _cx: &mut WindowContext) -> SharedString { + fn no_matches_text(&self, _window: &mut Window, _cx: &mut App) -> SharedString { "Enter the URL that you would like to fetch".into() } @@ -174,19 +175,30 @@ impl PickerDelegate for FetchContextPickerDelegate { 0 } - fn set_selected_index(&mut self, _ix: usize, _cx: &mut ViewContext>) {} + fn set_selected_index( + &mut self, + _ix: usize, + _window: &mut Window, + _cx: &mut Context>, + ) { + } - fn placeholder_text(&self, _cx: &mut WindowContext) -> Arc { + fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc { "Enter a URL…".into() } - fn update_matches(&mut self, query: String, _cx: &mut ViewContext>) -> Task<()> { + fn update_matches( + &mut self, + query: String, + _window: &mut Window, + _cx: &mut Context>, + ) -> Task<()> { self.url = query; Task::ready(()) } - fn confirm(&mut self, _secondary: bool, cx: &mut ViewContext>) { + fn confirm(&mut self, _secondary: bool, window: &mut Window, cx: &mut Context>) { let Some(workspace) = self.workspace.upgrade() else { return; }; @@ -194,13 +206,13 @@ impl PickerDelegate for FetchContextPickerDelegate { let http_client = workspace.read(cx).client().http_client().clone(); let url = self.url.clone(); let confirm_behavior = self.confirm_behavior; - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { let text = cx .background_executor() .spawn(Self::build_message(http_client, url.clone())) .await?; - this.update(&mut cx, |this, cx| { + this.update_in(&mut cx, |this, window, cx| { this.delegate .context_store .update(cx, |context_store, _cx| { @@ -209,7 +221,7 @@ impl PickerDelegate for FetchContextPickerDelegate { match confirm_behavior { ConfirmBehavior::KeepOpen => {} - ConfirmBehavior::Close => this.delegate.dismissed(cx), + ConfirmBehavior::Close => this.delegate.dismissed(window, cx), } anyhow::Ok(()) @@ -220,7 +232,7 @@ impl PickerDelegate for FetchContextPickerDelegate { .detach_and_log_err(cx); } - fn dismissed(&mut self, cx: &mut ViewContext>) { + fn dismissed(&mut self, _window: &mut Window, cx: &mut Context>) { self.context_picker .update(cx, |_, cx| { cx.emit(DismissEvent); @@ -232,7 +244,8 @@ impl PickerDelegate for FetchContextPickerDelegate { &self, ix: usize, selected: bool, - cx: &mut ViewContext>, + _window: &mut Window, + cx: &mut Context>, ) -> Option { let added = self.context_store.upgrade().map_or(false, |context_store| { context_store.read(cx).includes_url(&self.url).is_some() diff --git a/crates/assistant2/src/context_picker/file_context_picker.rs b/crates/assistant2/src/context_picker/file_context_picker.rs index 30624f5ee1..b68ae87145 100644 --- a/crates/assistant2/src/context_picker/file_context_picker.rs +++ b/crates/assistant2/src/context_picker/file_context_picker.rs @@ -11,8 +11,8 @@ use editor::{Anchor, Editor, FoldPlaceholder, ToPoint}; use file_icons::FileIcons; use fuzzy::PathMatch; use gpui::{ - AnyElement, AppContext, DismissEvent, Empty, FocusHandle, FocusableView, Stateful, Task, View, - WeakModel, WeakView, + AnyElement, App, DismissEvent, Empty, Entity, FocusHandle, Focusable, Stateful, Task, + WeakEntity, }; use multi_buffer::{MultiBufferPoint, MultiBufferRow}; use picker::{Picker, PickerDelegate}; @@ -27,17 +27,18 @@ use crate::context_picker::{ConfirmBehavior, ContextPicker}; use crate::context_store::{ContextStore, FileInclusion}; pub struct FileContextPicker { - picker: View>, + picker: Entity>, } impl FileContextPicker { pub fn new( - context_picker: WeakView, - workspace: WeakView, - editor: WeakView, - context_store: WeakModel, + context_picker: WeakEntity, + workspace: WeakEntity, + editor: WeakEntity, + context_store: WeakEntity, confirm_behavior: ConfirmBehavior, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Self { let delegate = FileContextPickerDelegate::new( context_picker, @@ -46,29 +47,29 @@ impl FileContextPicker { context_store, confirm_behavior, ); - let picker = cx.new_view(|cx| Picker::uniform_list(delegate, cx)); + let picker = cx.new(|cx| Picker::uniform_list(delegate, window, cx)); Self { picker } } } -impl FocusableView for FileContextPicker { - fn focus_handle(&self, cx: &AppContext) -> FocusHandle { +impl Focusable for FileContextPicker { + fn focus_handle(&self, cx: &App) -> FocusHandle { self.picker.focus_handle(cx) } } impl Render for FileContextPicker { - fn render(&mut self, _cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { self.picker.clone() } } pub struct FileContextPickerDelegate { - context_picker: WeakView, - workspace: WeakView, - editor: WeakView, - context_store: WeakModel, + context_picker: WeakEntity, + workspace: WeakEntity, + editor: WeakEntity, + context_store: WeakEntity, confirm_behavior: ConfirmBehavior, matches: Vec, selected_index: usize, @@ -76,10 +77,10 @@ pub struct FileContextPickerDelegate { impl FileContextPickerDelegate { pub fn new( - context_picker: WeakView, - workspace: WeakView, - editor: WeakView, - context_store: WeakModel, + context_picker: WeakEntity, + workspace: WeakEntity, + editor: WeakEntity, + context_store: WeakEntity, confirm_behavior: ConfirmBehavior, ) -> Self { Self { @@ -97,8 +98,9 @@ impl FileContextPickerDelegate { &mut self, query: String, cancellation_flag: Arc, - workspace: &View, - cx: &mut ViewContext>, + workspace: &Entity, + + cx: &mut Context>, ) -> Task> { if query.is_empty() { let workspace = workspace.read(cx); @@ -180,22 +182,32 @@ impl PickerDelegate for FileContextPickerDelegate { self.selected_index } - fn set_selected_index(&mut self, ix: usize, _cx: &mut ViewContext>) { + fn set_selected_index( + &mut self, + ix: usize, + _window: &mut Window, + _cx: &mut Context>, + ) { self.selected_index = ix; } - fn placeholder_text(&self, _cx: &mut WindowContext) -> Arc { + fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc { "Search files…".into() } - fn update_matches(&mut self, query: String, cx: &mut ViewContext>) -> Task<()> { + fn update_matches( + &mut self, + query: String, + window: &mut Window, + cx: &mut Context>, + ) -> Task<()> { let Some(workspace) = self.workspace.upgrade() else { return Task::ready(()); }; let search_task = self.search(query, Arc::::default(), &workspace, cx); - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { // TODO: This should be probably be run in the background. let paths = search_task.await; @@ -206,7 +218,7 @@ impl PickerDelegate for FileContextPickerDelegate { }) } - fn confirm(&mut self, _secondary: bool, cx: &mut ViewContext>) { + fn confirm(&mut self, _secondary: bool, window: &mut Window, cx: &mut Context>) { let Some(mat) = self.matches.get(self.selected_index) else { return; }; @@ -231,7 +243,7 @@ impl PickerDelegate for FileContextPickerDelegate { }; editor.update(cx, |editor, cx| { - editor.transact(cx, |editor, cx| { + editor.transact(window, cx, |editor, window, cx| { // Move empty selections left by 1 column to select the `@`s, so they get overwritten when we insert. { let mut selections = editor.selections.all::(cx); @@ -247,7 +259,9 @@ impl PickerDelegate for FileContextPickerDelegate { } } - editor.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); + editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| { + s.select(selections) + }); } let start_anchors = { @@ -260,7 +274,7 @@ impl PickerDelegate for FileContextPickerDelegate { .collect::>() }; - editor.insert(&full_path, cx); + editor.insert(&full_path, window, cx); let end_anchors = { let snapshot = editor.buffer().read(cx).snapshot(cx); @@ -272,14 +286,15 @@ impl PickerDelegate for FileContextPickerDelegate { .collect::>() }; - editor.insert("\n", cx); // Needed to end the fold + editor.insert("\n", window, cx); // Needed to end the fold let placeholder = FoldPlaceholder { render: render_fold_icon_button(IconName::File, file_name.into()), ..Default::default() }; - let render_trailer = move |_row, _unfold, _cx: &mut WindowContext| Empty.into_any(); + let render_trailer = + move |_row, _unfold, _window: &mut Window, _cx: &mut App| Empty.into_any(); let buffer = editor.buffer().read(cx).snapshot(cx); let mut rows_to_fold = BTreeSet::new(); @@ -300,7 +315,7 @@ impl PickerDelegate for FileContextPickerDelegate { editor.insert_creases(crease_iter, cx); for buffer_row in rows_to_fold { - editor.fold_at(&FoldAt { buffer_row }, cx); + editor.fold_at(&FoldAt { buffer_row }, window, cx); } }); }); @@ -316,19 +331,19 @@ impl PickerDelegate for FileContextPickerDelegate { }; let confirm_behavior = self.confirm_behavior; - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { match task.await.notify_async_err(&mut cx) { None => anyhow::Ok(()), - Some(()) => this.update(&mut cx, |this, cx| match confirm_behavior { + Some(()) => this.update_in(&mut cx, |this, window, cx| match confirm_behavior { ConfirmBehavior::KeepOpen => {} - ConfirmBehavior::Close => this.delegate.dismissed(cx), + ConfirmBehavior::Close => this.delegate.dismissed(window, cx), }), } }) .detach_and_log_err(cx); } - fn dismissed(&mut self, cx: &mut ViewContext>) { + fn dismissed(&mut self, _: &mut Window, cx: &mut Context>) { self.context_picker .update(cx, |_, cx| { cx.emit(DismissEvent); @@ -340,7 +355,8 @@ impl PickerDelegate for FileContextPickerDelegate { &self, ix: usize, selected: bool, - cx: &mut ViewContext>, + _window: &mut Window, + cx: &mut Context>, ) -> Option { let path_match = &self.matches[ix]; @@ -363,8 +379,8 @@ pub fn render_file_context_entry( id: ElementId, path: &Path, path_prefix: &Arc, - context_store: WeakModel, - cx: &WindowContext, + context_store: WeakEntity, + cx: &App, ) -> Stateful
{ let (file_name, directory) = if path == Path::new("") { (SharedString::from(path_prefix.clone()), None) @@ -437,7 +453,7 @@ pub fn render_file_context_entry( ) .child(Label::new("Included").size(LabelSize::Small)), ) - .tooltip(move |cx| Tooltip::text(format!("in {dir_name}"), cx)) + .tooltip(Tooltip::text(format!("in {dir_name}"))) } }) } @@ -445,8 +461,8 @@ pub fn render_file_context_entry( fn render_fold_icon_button( icon: IconName, label: SharedString, -) -> Arc, &mut WindowContext) -> AnyElement> { - Arc::new(move |fold_id, _fold_range, _cx| { +) -> Arc, &mut Window, &mut App) -> AnyElement> { + Arc::new(move |fold_id, _fold_range, _window, _cx| { ButtonLike::new(fold_id) .style(ButtonStyle::Filled) .layer(ElevationIndex::ElevatedSurface) @@ -461,13 +477,14 @@ fn fold_toggle( ) -> impl Fn( MultiBufferRow, bool, - Arc, - &mut WindowContext, + Arc, + &mut Window, + &mut App, ) -> AnyElement { - move |row, is_folded, fold, _cx| { + move |row, is_folded, fold, _window, _cx| { Disclosure::new((name, row.0 as u64), !is_folded) .toggle_state(is_folded) - .on_click(move |_e, cx| fold(!is_folded, cx)) + .on_click(move |_e, window, cx| fold(!is_folded, window, cx)) .into_any_element() } } diff --git a/crates/assistant2/src/context_picker/thread_context_picker.rs b/crates/assistant2/src/context_picker/thread_context_picker.rs index e6a89f8692..e0dd0cef08 100644 --- a/crates/assistant2/src/context_picker/thread_context_picker.rs +++ b/crates/assistant2/src/context_picker/thread_context_picker.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use fuzzy::StringMatchCandidate; -use gpui::{AppContext, DismissEvent, FocusHandle, FocusableView, Task, View, WeakModel, WeakView}; +use gpui::{App, DismissEvent, Entity, FocusHandle, Focusable, Task, WeakEntity}; use picker::{Picker, PickerDelegate}; use ui::{prelude::*, ListItem}; @@ -11,16 +11,17 @@ use crate::thread::ThreadId; use crate::thread_store::ThreadStore; pub struct ThreadContextPicker { - picker: View>, + picker: Entity>, } impl ThreadContextPicker { pub fn new( - thread_store: WeakModel, - context_picker: WeakView, - context_store: WeakModel, + thread_store: WeakEntity, + context_picker: WeakEntity, + context_store: WeakEntity, confirm_behavior: ConfirmBehavior, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Self { let delegate = ThreadContextPickerDelegate::new( thread_store, @@ -28,20 +29,20 @@ impl ThreadContextPicker { context_store, confirm_behavior, ); - let picker = cx.new_view(|cx| Picker::uniform_list(delegate, cx)); + let picker = cx.new(|cx| Picker::uniform_list(delegate, window, cx)); ThreadContextPicker { picker } } } -impl FocusableView for ThreadContextPicker { - fn focus_handle(&self, cx: &AppContext) -> FocusHandle { +impl Focusable for ThreadContextPicker { + fn focus_handle(&self, cx: &App) -> FocusHandle { self.picker.focus_handle(cx) } } impl Render for ThreadContextPicker { - fn render(&mut self, _cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { self.picker.clone() } } @@ -53,9 +54,9 @@ pub struct ThreadContextEntry { } pub struct ThreadContextPickerDelegate { - thread_store: WeakModel, - context_picker: WeakView, - context_store: WeakModel, + thread_store: WeakEntity, + context_picker: WeakEntity, + context_store: WeakEntity, confirm_behavior: ConfirmBehavior, matches: Vec, selected_index: usize, @@ -63,9 +64,9 @@ pub struct ThreadContextPickerDelegate { impl ThreadContextPickerDelegate { pub fn new( - thread_store: WeakModel, - context_picker: WeakView, - context_store: WeakModel, + thread_store: WeakEntity, + context_picker: WeakEntity, + context_store: WeakEntity, confirm_behavior: ConfirmBehavior, ) -> Self { ThreadContextPickerDelegate { @@ -90,15 +91,25 @@ impl PickerDelegate for ThreadContextPickerDelegate { self.selected_index } - fn set_selected_index(&mut self, ix: usize, _cx: &mut ViewContext>) { + fn set_selected_index( + &mut self, + ix: usize, + _window: &mut Window, + _cx: &mut Context>, + ) { self.selected_index = ix; } - fn placeholder_text(&self, _cx: &mut WindowContext) -> Arc { + fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc { "Search threads…".into() } - fn update_matches(&mut self, query: String, cx: &mut ViewContext>) -> Task<()> { + fn update_matches( + &mut self, + query: String, + window: &mut Window, + cx: &mut Context>, + ) -> Task<()> { let Ok(threads) = self.thread_store.update(cx, |this, _cx| { this.threads() .into_iter() @@ -138,7 +149,7 @@ impl PickerDelegate for ThreadContextPickerDelegate { } }); - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { let matches = search_task.await; this.update(&mut cx, |this, cx| { this.delegate.matches = matches; @@ -149,7 +160,7 @@ impl PickerDelegate for ThreadContextPickerDelegate { }) } - fn confirm(&mut self, _secondary: bool, cx: &mut ViewContext>) { + fn confirm(&mut self, _secondary: bool, window: &mut Window, cx: &mut Context>) { let Some(entry) = self.matches.get(self.selected_index) else { return; }; @@ -160,9 +171,9 @@ impl PickerDelegate for ThreadContextPickerDelegate { let open_thread_task = thread_store.update(cx, |this, cx| this.open_thread(&entry.id, cx)); - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { let thread = open_thread_task.await?; - this.update(&mut cx, |this, cx| { + this.update_in(&mut cx, |this, window, cx| { this.delegate .context_store .update(cx, |context_store, cx| context_store.add_thread(thread, cx)) @@ -170,14 +181,14 @@ impl PickerDelegate for ThreadContextPickerDelegate { match this.delegate.confirm_behavior { ConfirmBehavior::KeepOpen => {} - ConfirmBehavior::Close => this.delegate.dismissed(cx), + ConfirmBehavior::Close => this.delegate.dismissed(window, cx), } }) }) .detach_and_log_err(cx); } - fn dismissed(&mut self, cx: &mut ViewContext>) { + fn dismissed(&mut self, _window: &mut Window, cx: &mut Context>) { self.context_picker .update(cx, |_, cx| { cx.emit(DismissEvent); @@ -189,7 +200,8 @@ impl PickerDelegate for ThreadContextPickerDelegate { &self, ix: usize, selected: bool, - cx: &mut ViewContext>, + _window: &mut Window, + cx: &mut Context>, ) -> Option { let thread = &self.matches[ix]; @@ -201,8 +213,8 @@ impl PickerDelegate for ThreadContextPickerDelegate { pub fn render_thread_context_entry( thread: &ThreadContextEntry, - context_store: WeakModel, - cx: &mut WindowContext, + context_store: WeakEntity, + cx: &mut App, ) -> Div { let added = context_store.upgrade().map_or(false, |ctx_store| { ctx_store.read(cx).includes_thread(&thread.id).is_some() diff --git a/crates/assistant2/src/context_store.rs b/crates/assistant2/src/context_store.rs index f6b2d5c38f..0cacaf31bc 100644 --- a/crates/assistant2/src/context_store.rs +++ b/crates/assistant2/src/context_store.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use anyhow::{anyhow, bail, Result}; use collections::{BTreeMap, HashMap, HashSet}; use futures::{self, future, Future, FutureExt}; -use gpui::{AppContext, AsyncAppContext, Model, ModelContext, SharedString, Task, WeakView}; +use gpui::{App, AsyncAppContext, Context, Entity, SharedString, Task, WeakEntity}; use language::Buffer; use project::{ProjectPath, Worktree}; use rope::Rope; @@ -12,15 +12,15 @@ use text::BufferId; use workspace::Workspace; use crate::context::{ - Context, ContextBuffer, ContextId, ContextSnapshot, DirectoryContext, FetchedUrlContext, - FileContext, ThreadContext, + AssistantContext, ContextBuffer, ContextId, ContextSnapshot, DirectoryContext, + FetchedUrlContext, FileContext, ThreadContext, }; use crate::context_strip::SuggestedContext; use crate::thread::{Thread, ThreadId}; pub struct ContextStore { - workspace: WeakView, - context: Vec, + workspace: WeakEntity, + context: Vec, // TODO: If an EntityId is used for all context types (like BufferId), can remove ContextId. next_context_id: ContextId, files: BTreeMap, @@ -30,7 +30,7 @@ pub struct ContextStore { } impl ContextStore { - pub fn new(workspace: WeakView) -> Self { + pub fn new(workspace: WeakEntity) -> Self { Self { workspace, context: Vec::new(), @@ -42,16 +42,13 @@ impl ContextStore { } } - pub fn snapshot<'a>( - &'a self, - cx: &'a AppContext, - ) -> impl Iterator + 'a { + pub fn snapshot<'a>(&'a self, cx: &'a App) -> impl Iterator + 'a { self.context() .iter() .flat_map(|context| context.snapshot(cx)) } - pub fn context(&self) -> &Vec { + pub fn context(&self) -> &Vec { &self.context } @@ -66,7 +63,7 @@ impl ContextStore { pub fn add_file_from_path( &mut self, project_path: ProjectPath, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { let workspace = self.workspace.clone(); @@ -122,8 +119,8 @@ impl ContextStore { pub fn add_file_from_buffer( &mut self, - buffer_model: Model, - cx: &mut ModelContext, + buffer_model: Entity, + cx: &mut Context, ) -> Task> { cx.spawn(|this, mut cx| async move { let (buffer_info, text_task) = this.update(&mut cx, |_, cx| { @@ -153,13 +150,13 @@ impl ContextStore { let id = self.next_context_id.post_inc(); self.files.insert(context_buffer.id, id); self.context - .push(Context::File(FileContext { id, context_buffer })); + .push(AssistantContext::File(FileContext { id, context_buffer })); } pub fn add_directory( &mut self, project_path: ProjectPath, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { let workspace = self.workspace.clone(); let Some(project) = workspace @@ -244,14 +241,15 @@ impl ContextStore { let id = self.next_context_id.post_inc(); self.directories.insert(path.to_path_buf(), id); - self.context.push(Context::Directory(DirectoryContext::new( - id, - path, - context_buffers, - ))); + self.context + .push(AssistantContext::Directory(DirectoryContext::new( + id, + path, + context_buffers, + ))); } - pub fn add_thread(&mut self, thread: Model, cx: &mut ModelContext) { + pub fn add_thread(&mut self, thread: Entity, cx: &mut Context) { if let Some(context_id) = self.includes_thread(&thread.read(cx).id()) { self.remove_context(context_id); } else { @@ -259,13 +257,13 @@ impl ContextStore { } } - fn insert_thread(&mut self, thread: Model, cx: &AppContext) { + fn insert_thread(&mut self, thread: Entity, cx: &App) { let id = self.next_context_id.post_inc(); let text = thread.read(cx).text().into(); self.threads.insert(thread.read(cx).id().clone(), id); self.context - .push(Context::Thread(ThreadContext { id, thread, text })); + .push(AssistantContext::Thread(ThreadContext { id, thread, text })); } pub fn add_fetched_url(&mut self, url: String, text: impl Into) { @@ -278,17 +276,18 @@ impl ContextStore { let id = self.next_context_id.post_inc(); self.fetched_urls.insert(url.clone(), id); - self.context.push(Context::FetchedUrl(FetchedUrlContext { - id, - url: url.into(), - text: text.into(), - })); + self.context + .push(AssistantContext::FetchedUrl(FetchedUrlContext { + id, + url: url.into(), + text: text.into(), + })); } pub fn accept_suggested_context( &mut self, suggested: &SuggestedContext, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { match suggested { SuggestedContext::File { @@ -315,16 +314,16 @@ impl ContextStore { }; match self.context.remove(ix) { - Context::File(_) => { + AssistantContext::File(_) => { self.files.retain(|_, context_id| *context_id != id); } - Context::Directory(_) => { + AssistantContext::Directory(_) => { self.directories.retain(|_, context_id| *context_id != id); } - Context::FetchedUrl(_) => { + AssistantContext::FetchedUrl(_) => { self.fetched_urls.retain(|_, context_id| *context_id != id); } - Context::Thread(_) => { + AssistantContext::Thread(_) => { self.threads.retain(|_, context_id| *context_id != id); } } @@ -343,10 +342,10 @@ impl ContextStore { /// Returns whether this file path is already included directly in the context, or if it will be /// included in the context via a directory. - pub fn will_include_file_path(&self, path: &Path, cx: &AppContext) -> Option { + pub fn will_include_file_path(&self, path: &Path, cx: &App) -> Option { if !self.files.is_empty() { let found_file_context = self.context.iter().find(|context| match &context { - Context::File(file_context) => { + AssistantContext::File(file_context) => { let buffer = file_context.context_buffer.buffer.read(cx); if let Some(file_path) = buffer_path_log_err(buffer) { *file_path == *path @@ -393,7 +392,7 @@ impl ContextStore { } /// Replaces the context that matches the ID of the new context, if any match. - fn replace_context(&mut self, new_context: Context) { + fn replace_context(&mut self, new_context: AssistantContext) { let id = new_context.id(); for context in self.context.iter_mut() { if context.id() == id { @@ -403,15 +402,17 @@ impl ContextStore { } } - pub fn file_paths(&self, cx: &AppContext) -> HashSet { + pub fn file_paths(&self, cx: &App) -> HashSet { self.context .iter() .filter_map(|context| match context { - Context::File(file) => { + AssistantContext::File(file) => { let buffer = file.context_buffer.buffer.read(cx); buffer_path_log_err(buffer).map(|p| p.to_path_buf()) } - Context::Directory(_) | Context::FetchedUrl(_) | Context::Thread(_) => None, + AssistantContext::Directory(_) + | AssistantContext::FetchedUrl(_) + | AssistantContext::Thread(_) => None, }) .collect() } @@ -428,7 +429,7 @@ pub enum FileInclusion { // ContextBuffer without text. struct BufferInfo { - buffer_model: Model, + buffer_model: Entity, id: BufferId, version: clock::Global, } @@ -444,7 +445,7 @@ fn make_context_buffer(info: BufferInfo, text: SharedString) -> ContextBuffer { fn collect_buffer_info_and_text( path: Arc, - buffer_model: Model, + buffer_model: Entity, buffer: &Buffer, cx: AsyncAppContext, ) -> (BufferInfo, Task) { @@ -525,32 +526,32 @@ fn collect_files_in_path(worktree: &Worktree, path: &Path) -> Vec> { } pub fn refresh_context_store_text( - context_store: Model, - cx: &AppContext, + context_store: Entity, + cx: &App, ) -> impl Future { let mut tasks = Vec::new(); for context in &context_store.read(cx).context { match context { - Context::File(file_context) => { + AssistantContext::File(file_context) => { let context_store = context_store.clone(); if let Some(task) = refresh_file_text(context_store, file_context, cx) { tasks.push(task); } } - Context::Directory(directory_context) => { + AssistantContext::Directory(directory_context) => { let context_store = context_store.clone(); if let Some(task) = refresh_directory_text(context_store, directory_context, cx) { tasks.push(task); } } - Context::Thread(thread_context) => { + AssistantContext::Thread(thread_context) => { let context_store = context_store.clone(); tasks.push(refresh_thread_text(context_store, thread_context, cx)); } // Intentionally omit refreshing fetched URLs as it doesn't seem all that useful, // and doing the caching properly could be tricky (unless it's already handled by // the HttpClient?). - Context::FetchedUrl(_) => {} + AssistantContext::FetchedUrl(_) => {} } } @@ -558,9 +559,9 @@ pub fn refresh_context_store_text( } fn refresh_file_text( - context_store: Model, + context_store: Entity, file_context: &FileContext, - cx: &AppContext, + cx: &App, ) -> Option> { let id = file_context.id; let task = refresh_context_buffer(&file_context.context_buffer, cx); @@ -570,7 +571,7 @@ fn refresh_file_text( context_store .update(&mut cx, |context_store, _| { let new_file_context = FileContext { id, context_buffer }; - context_store.replace_context(Context::File(new_file_context)); + context_store.replace_context(AssistantContext::File(new_file_context)); }) .ok(); })) @@ -580,9 +581,9 @@ fn refresh_file_text( } fn refresh_directory_text( - context_store: Model, + context_store: Entity, directory_context: &DirectoryContext, - cx: &AppContext, + cx: &App, ) -> Option> { let mut stale = false; let futures = directory_context @@ -611,16 +612,16 @@ fn refresh_directory_text( context_store .update(&mut cx, |context_store, _| { let new_directory_context = DirectoryContext::new(id, &path, context_buffers); - context_store.replace_context(Context::Directory(new_directory_context)); + context_store.replace_context(AssistantContext::Directory(new_directory_context)); }) .ok(); })) } fn refresh_thread_text( - context_store: Model, + context_store: Entity, thread_context: &ThreadContext, - cx: &AppContext, + cx: &App, ) -> Task<()> { let id = thread_context.id; let thread = thread_context.thread.clone(); @@ -628,7 +629,11 @@ fn refresh_thread_text( context_store .update(&mut cx, |context_store, cx| { let text = thread.read(cx).text().into(); - context_store.replace_context(Context::Thread(ThreadContext { id, thread, text })); + context_store.replace_context(AssistantContext::Thread(ThreadContext { + id, + thread, + text, + })); }) .ok(); }) @@ -636,7 +641,7 @@ fn refresh_thread_text( fn refresh_context_buffer( context_buffer: &ContextBuffer, - cx: &AppContext, + cx: &App, ) -> Option> { let buffer = context_buffer.buffer.read(cx); let path = buffer_path_log_err(buffer)?; diff --git a/crates/assistant2/src/context_strip.rs b/crates/assistant2/src/context_strip.rs index 9e69d1eea9..e0c2073021 100644 --- a/crates/assistant2/src/context_strip.rs +++ b/crates/assistant2/src/context_strip.rs @@ -4,8 +4,8 @@ use collections::HashSet; use editor::Editor; use file_icons::FileIcons; use gpui::{ - AppContext, Bounds, DismissEvent, EventEmitter, FocusHandle, FocusableView, Model, - Subscription, View, WeakModel, WeakView, + App, Bounds, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, Subscription, + WeakEntity, }; use itertools::Itertools; use language::Buffer; @@ -24,34 +24,37 @@ use crate::{ }; pub struct ContextStrip { - context_store: Model, - pub context_picker: View, + context_store: Entity, + pub context_picker: Entity, context_picker_menu_handle: PopoverMenuHandle, focus_handle: FocusHandle, suggest_context_kind: SuggestContextKind, - workspace: WeakView, + workspace: WeakEntity, _subscriptions: Vec, focused_index: Option, children_bounds: Option>>, } impl ContextStrip { + #[allow(clippy::too_many_arguments)] pub fn new( - context_store: Model, - workspace: WeakView, - editor: WeakView, - thread_store: Option>, + context_store: Entity, + workspace: WeakEntity, + editor: WeakEntity, + thread_store: Option>, context_picker_menu_handle: PopoverMenuHandle, suggest_context_kind: SuggestContextKind, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Self { - let context_picker = cx.new_view(|cx| { + let context_picker = cx.new(|cx| { ContextPicker::new( workspace.clone(), thread_store.clone(), context_store.downgrade(), editor.clone(), ConfirmBehavior::KeepOpen, + window, cx, ) }); @@ -59,9 +62,9 @@ impl ContextStrip { let focus_handle = cx.focus_handle(); let subscriptions = vec![ - cx.subscribe(&context_picker, Self::handle_context_picker_event), - cx.on_focus(&focus_handle, Self::handle_focus), - cx.on_blur(&focus_handle, Self::handle_blur), + cx.subscribe_in(&context_picker, window, Self::handle_context_picker_event), + cx.on_focus(&focus_handle, window, Self::handle_focus), + cx.on_blur(&focus_handle, window, Self::handle_blur), ]; Self { @@ -77,14 +80,14 @@ impl ContextStrip { } } - fn suggested_context(&self, cx: &ViewContext) -> Option { + fn suggested_context(&self, cx: &Context) -> Option { match self.suggest_context_kind { SuggestContextKind::File => self.suggested_file(cx), SuggestContextKind::Thread => self.suggested_thread(cx), } } - fn suggested_file(&self, cx: &ViewContext) -> Option { + fn suggested_file(&self, cx: &Context) -> Option { let workspace = self.workspace.upgrade()?; let active_item = workspace.read(cx).active_item(cx)?; @@ -117,7 +120,7 @@ impl ContextStrip { }) } - fn suggested_thread(&self, cx: &ViewContext) -> Option { + fn suggested_thread(&self, cx: &Context) -> Option { if !self.context_picker.read(cx).allow_threads() { return None; } @@ -149,24 +152,25 @@ impl ContextStrip { fn handle_context_picker_event( &mut self, - _picker: View, + _picker: &Entity, _event: &DismissEvent, - cx: &mut ViewContext, + _window: &mut Window, + cx: &mut Context, ) { cx.emit(ContextStripEvent::PickerDismissed); } - fn handle_focus(&mut self, cx: &mut ViewContext) { + fn handle_focus(&mut self, _window: &mut Window, cx: &mut Context) { self.focused_index = self.last_pill_index(); cx.notify(); } - fn handle_blur(&mut self, cx: &mut ViewContext) { + fn handle_blur(&mut self, _window: &mut Window, cx: &mut Context) { self.focused_index = None; cx.notify(); } - fn focus_left(&mut self, _: &FocusLeft, cx: &mut ViewContext) { + fn focus_left(&mut self, _: &FocusLeft, _window: &mut Window, cx: &mut Context) { self.focused_index = match self.focused_index { Some(index) if index > 0 => Some(index - 1), _ => self.last_pill_index(), @@ -175,7 +179,7 @@ impl ContextStrip { cx.notify(); } - fn focus_right(&mut self, _: &FocusRight, cx: &mut ViewContext) { + fn focus_right(&mut self, _: &FocusRight, _window: &mut Window, cx: &mut Context) { let Some(last_index) = self.last_pill_index() else { return; }; @@ -188,7 +192,7 @@ impl ContextStrip { cx.notify(); } - fn focus_up(&mut self, _: &FocusUp, cx: &mut ViewContext) { + fn focus_up(&mut self, _: &FocusUp, _window: &mut Window, cx: &mut Context) { let Some(focused_index) = self.focused_index else { return; }; @@ -206,7 +210,7 @@ impl ContextStrip { cx.notify(); } - fn focus_down(&mut self, _: &FocusDown, cx: &mut ViewContext) { + fn focus_down(&mut self, _: &FocusDown, _window: &mut Window, cx: &mut Context) { let Some(focused_index) = self.focused_index else { return; }; @@ -276,7 +280,12 @@ impl ContextStrip { best.map(|(index, _, _)| index) } - fn remove_focused_context(&mut self, _: &RemoveFocusedContext, cx: &mut ViewContext) { + fn remove_focused_context( + &mut self, + _: &RemoveFocusedContext, + _window: &mut Window, + cx: &mut Context, + ) { if let Some(index) = self.focused_index { let mut is_empty = false; @@ -302,22 +311,32 @@ impl ContextStrip { self.focused_index == Some(context.len()) } - fn accept_suggested_context(&mut self, _: &AcceptSuggestedContext, cx: &mut ViewContext) { + fn accept_suggested_context( + &mut self, + _: &AcceptSuggestedContext, + window: &mut Window, + cx: &mut Context, + ) { if let Some(suggested) = self.suggested_context(cx) { let context_store = self.context_store.read(cx); if self.is_suggested_focused(context_store.context()) { - self.add_suggested_context(&suggested, cx); + self.add_suggested_context(&suggested, window, cx); } } } - fn add_suggested_context(&mut self, suggested: &SuggestedContext, cx: &mut ViewContext) { + fn add_suggested_context( + &mut self, + suggested: &SuggestedContext, + window: &mut Window, + cx: &mut Context, + ) { let task = self.context_store.update(cx, |context_store, cx| { context_store.accept_suggested_context(&suggested, cx) }); - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { match task.await.notify_async_err(&mut cx) { None => {} Some(()) => { @@ -334,14 +353,14 @@ impl ContextStrip { } } -impl FocusableView for ContextStrip { - fn focus_handle(&self, _cx: &AppContext) -> FocusHandle { +impl Focusable for ContextStrip { + fn focus_handle(&self, _cx: &App) -> FocusHandle { self.focus_handle.clone() } } impl Render for ContextStrip { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { let context_store = self.context_store.read(cx); let context = context_store .context() @@ -374,19 +393,20 @@ impl Render for ContextStrip { .on_action(cx.listener(Self::remove_focused_context)) .on_action(cx.listener(Self::accept_suggested_context)) .on_children_prepainted({ - let view = cx.view().downgrade(); - move |children_bounds, cx| { - view.update(cx, |this, _| { - this.children_bounds = Some(children_bounds); - }) - .ok(); + let model = cx.model().downgrade(); + move |children_bounds, _window, cx| { + model + .update(cx, |this, _| { + this.children_bounds = Some(children_bounds); + }) + .ok(); } }) .child( PopoverMenu::new("context-picker") - .menu(move |cx| { + .menu(move |window, cx| { context_picker.update(cx, |this, cx| { - this.init(cx); + this.init(window, cx); }); Some(context_picker.clone()) @@ -397,12 +417,12 @@ impl Render for ContextStrip { .style(ui::ButtonStyle::Filled) .tooltip({ let focus_handle = focus_handle.clone(); - - move |cx| { + move |window, cx| { Tooltip::for_action_in( "Add Context", &ToggleContextPicker, &focus_handle, + window, cx, ) } @@ -429,8 +449,12 @@ impl Render for ContextStrip { ) .opacity(0.5) .children( - KeyBinding::for_action_in(&ToggleContextPicker, &focus_handle, cx) - .map(|binding| binding.into_any_element()), + KeyBinding::for_action_in( + &ToggleContextPicker, + &focus_handle, + window, + ) + .map(|binding| binding.into_any_element()), ), ) } @@ -443,7 +467,7 @@ impl Render for ContextStrip { Some({ let id = context.id; let context_store = self.context_store.clone(); - Rc::new(cx.listener(move |_this, _event, cx| { + Rc::new(cx.listener(move |_this, _event, _window, cx| { context_store.update(cx, |this, _cx| { this.remove_context(id); }); @@ -451,7 +475,7 @@ impl Render for ContextStrip { })) }), ) - .on_click(Rc::new(cx.listener(move |this, _, cx| { + .on_click(Rc::new(cx.listener(move |this, _, _window, cx| { this.focused_index = Some(i); cx.notify(); }))) @@ -464,9 +488,11 @@ impl Render for ContextStrip { suggested.kind(), self.is_suggested_focused(&context), ) - .on_click(Rc::new(cx.listener(move |this, _event, cx| { - this.add_suggested_context(&suggested, cx); - }))), + .on_click(Rc::new(cx.listener( + move |this, _event, window, cx| { + this.add_suggested_context(&suggested, window, cx); + }, + ))), ) }) .when(!context.is_empty(), { @@ -476,19 +502,20 @@ impl Render for ContextStrip { .icon_size(IconSize::Small) .tooltip({ let focus_handle = focus_handle.clone(); - move |cx| { + move |window, cx| { Tooltip::for_action_in( "Remove All Context", &RemoveAllContext, &focus_handle, + window, cx, ) } }) .on_click(cx.listener({ let focus_handle = focus_handle.clone(); - move |_this, _event, cx| { - focus_handle.dispatch_action(&RemoveAllContext, cx); + move |_this, _event, window, cx| { + focus_handle.dispatch_action(&RemoveAllContext, window, cx); } })), ) @@ -516,11 +543,11 @@ pub enum SuggestedContext { File { name: SharedString, icon_path: Option, - buffer: WeakModel, + buffer: WeakEntity, }, Thread { name: SharedString, - thread: WeakModel, + thread: WeakEntity, }, } diff --git a/crates/assistant2/src/inline_assistant.rs b/crates/assistant2/src/inline_assistant.rs index 55e6666c77..09fe77ec3b 100644 --- a/crates/assistant2/src/inline_assistant.rs +++ b/crates/assistant2/src/inline_assistant.rs @@ -20,8 +20,8 @@ use editor::{ use feature_flags::{Assistant2FeatureFlag, FeatureFlagViewExt as _}; use fs::Fs; use gpui::{ - point, AppContext, FocusableView, Global, HighlightStyle, Model, Subscription, Task, - UpdateGlobal, View, ViewContext, WeakModel, WeakView, WindowContext, + point, App, Context, Entity, Focusable, Global, HighlightStyle, Subscription, Task, + UpdateGlobal, WeakEntity, Window, }; use language::{Buffer, Point, Selection, TransactionId}; use language_model::LanguageModelRegistry; @@ -51,17 +51,20 @@ pub fn init( fs: Arc, prompt_builder: Arc, telemetry: Arc, - cx: &mut AppContext, + cx: &mut App, ) { cx.set_global(InlineAssistant::new(fs, prompt_builder, telemetry)); - cx.observe_new_views(|_workspace: &mut Workspace, cx| { - let workspace = cx.view().clone(); + cx.observe_new(|_workspace: &mut Workspace, window, cx| { + let Some(window) = window else { + return; + }; + let workspace = cx.model().clone(); InlineAssistant::update_global(cx, |inline_assistant, cx| { - inline_assistant.register_workspace(&workspace, cx) + inline_assistant.register_workspace(&workspace, window, cx) }); - cx.observe_flag::({ - |is_assistant2_enabled, _view, cx| { + cx.observe_flag::(window, { + |is_assistant2_enabled, _workspace, _window, cx| { InlineAssistant::update_global(cx, |inline_assistant, _cx| { inline_assistant.is_assistant2_enabled = is_assistant2_enabled; }); @@ -75,17 +78,17 @@ pub fn init( const PROMPT_HISTORY_MAX_LEN: usize = 20; enum InlineAssistTarget { - Editor(View), - Terminal(View), + Editor(Entity), + Terminal(Entity), } pub struct InlineAssistant { next_assist_id: InlineAssistId, next_assist_group_id: InlineAssistGroupId, assists: HashMap, - assists_by_editor: HashMap, EditorInlineAssists>, + assists_by_editor: HashMap, EditorInlineAssists>, assist_groups: HashMap, - confirmed_assists: HashMap>, + confirmed_assists: HashMap>, prompt_history: VecDeque, prompt_builder: Arc, telemetry: Arc, @@ -116,13 +119,19 @@ impl InlineAssistant { } } - pub fn register_workspace(&mut self, workspace: &View, cx: &mut WindowContext) { - cx.subscribe(workspace, |workspace, event, cx| { - Self::update_global(cx, |this, cx| { - this.handle_workspace_event(workspace, event, cx) - }); - }) - .detach(); + pub fn register_workspace( + &mut self, + workspace: &Entity, + window: &mut Window, + cx: &mut App, + ) { + window + .subscribe(workspace, cx, |workspace, event, window, cx| { + Self::update_global(cx, |this, cx| { + this.handle_workspace_event(workspace, event, window, cx) + }); + }) + .detach(); let workspace = workspace.downgrade(); cx.observe_global::(move |cx| { @@ -142,9 +151,10 @@ impl InlineAssistant { fn handle_workspace_event( &mut self, - workspace: View, + workspace: Entity, event: &workspace::Event, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { match event { workspace::Event::UserSavedItem { item, .. } => { @@ -154,14 +164,14 @@ impl InlineAssistant { for assist_id in editor_assists.assist_ids.clone() { let assist = &self.assists[&assist_id]; if let CodegenStatus::Done = assist.codegen.read(cx).status(cx) { - self.finish_assist(assist_id, false, cx) + self.finish_assist(assist_id, false, window, cx) } } } } } workspace::Event::ItemAdded { item } => { - self.register_workspace_item(&workspace, item.as_ref(), cx); + self.register_workspace_item(&workspace, item.as_ref(), window, cx); } _ => (), } @@ -169,9 +179,10 @@ impl InlineAssistant { fn register_workspace_item( &mut self, - workspace: &View, + workspace: &Entity, item: &dyn ItemHandle, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { let is_assistant2_enabled = self.is_assistant2_enabled; @@ -185,18 +196,22 @@ impl InlineAssistant { editor.add_code_action_provider( Rc::new(AssistantCodeActionProvider { - editor: cx.view().downgrade(), + editor: cx.model().downgrade(), workspace: workspace.downgrade(), thread_store, }), + window, cx, ); // Remove the Assistant1 code action provider, as it still might be registered. - editor.remove_code_action_provider("assistant".into(), cx); + editor.remove_code_action_provider("assistant".into(), window, cx); } else { - editor - .remove_code_action_provider(ASSISTANT_CODE_ACTION_PROVIDER_ID.into(), cx); + editor.remove_code_action_provider( + ASSISTANT_CODE_ACTION_PROVIDER_ID.into(), + window, + cx, + ); } }); } @@ -205,14 +220,16 @@ impl InlineAssistant { pub fn inline_assist( workspace: &mut Workspace, _action: &zed_actions::assistant::InlineAssist, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let settings = AssistantSettings::get_global(cx); if !settings.enabled { return; } - let Some(inline_assist_target) = Self::resolve_inline_assist_target(workspace, cx) else { + let Some(inline_assist_target) = Self::resolve_inline_assist_target(workspace, window, cx) + else { return; }; @@ -226,24 +243,37 @@ impl InlineAssistant { .panel::(cx) .map(|assistant_panel| assistant_panel.read(cx).thread_store().downgrade()); - let handle_assist = |cx: &mut ViewContext| match inline_assist_target { - InlineAssistTarget::Editor(active_editor) => { - InlineAssistant::update_global(cx, |assistant, cx| { - assistant.assist(&active_editor, cx.view().downgrade(), thread_store, cx) - }) - } - InlineAssistTarget::Terminal(active_terminal) => { - TerminalInlineAssistant::update_global(cx, |assistant, cx| { - assistant.assist(&active_terminal, cx.view().downgrade(), thread_store, cx) - }) - } - }; + let handle_assist = + |window: &mut Window, cx: &mut Context| match inline_assist_target { + InlineAssistTarget::Editor(active_editor) => { + InlineAssistant::update_global(cx, |assistant, cx| { + assistant.assist( + &active_editor, + cx.model().downgrade(), + thread_store, + window, + cx, + ) + }) + } + InlineAssistTarget::Terminal(active_terminal) => { + TerminalInlineAssistant::update_global(cx, |assistant, cx| { + assistant.assist( + &active_terminal, + cx.model().downgrade(), + thread_store, + window, + cx, + ) + }) + } + }; if is_authenticated() { - handle_assist(cx); + handle_assist(window, cx); } else { - cx.spawn(|_workspace, mut cx| async move { - let Some(task) = cx.update(|cx| { + cx.spawn_in(window, |_workspace, mut cx| async move { + let Some(task) = cx.update(|_, cx| { LanguageModelRegistry::read_global(cx) .active_provider() .map_or(None, |provider| Some(provider.authenticate(cx))) @@ -260,8 +290,10 @@ impl InlineAssistant { .ok(); if let Some(answer) = answer { if answer == 0 { - cx.update(|cx| cx.dispatch_action(Box::new(ShowConfiguration))) - .ok(); + cx.update(|window, cx| { + window.dispatch_action(Box::new(ShowConfiguration), cx) + }) + .ok(); } } return Ok(()); @@ -273,17 +305,18 @@ impl InlineAssistant { .detach_and_log_err(cx); if is_authenticated() { - handle_assist(cx); + handle_assist(window, cx); } } } pub fn assist( &mut self, - editor: &View, - workspace: WeakView, - thread_store: Option>, - cx: &mut WindowContext, + editor: &Entity, + workspace: WeakEntity, + thread_store: Option>, + window: &mut Window, + cx: &mut App, ) { let (snapshot, initial_selections) = editor.update(cx, |editor, cx| { ( @@ -349,16 +382,15 @@ impl InlineAssistant { } let assist_group_id = self.next_assist_group_id.post_inc(); - let prompt_buffer = cx.new_model(|cx| { - MultiBuffer::singleton(cx.new_model(|cx| Buffer::local(String::new(), cx)), cx) - }); + let prompt_buffer = + cx.new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(String::new(), cx)), cx)); let mut assists = Vec::new(); let mut assist_to_focus = None; for range in codegen_ranges { let assist_id = self.next_assist_id.post_inc(); - let context_store = cx.new_model(|_cx| ContextStore::new(workspace.clone())); - let codegen = cx.new_model(|cx| { + let context_store = cx.new(|_cx| ContextStore::new(workspace.clone())); + let codegen = cx.new(|cx| { BufferCodegen::new( editor.read(cx).buffer().clone(), range.clone(), @@ -371,7 +403,7 @@ impl InlineAssistant { }); let gutter_dimensions = Arc::new(Mutex::new(GutterDimensions::default())); - let prompt_editor = cx.new_view(|cx| { + let prompt_editor = cx.new(|cx| { PromptEditor::new_buffer( assist_id, gutter_dimensions.clone(), @@ -382,6 +414,7 @@ impl InlineAssistant { context_store, workspace.clone(), thread_store.clone(), + window, cx, ) }); @@ -412,7 +445,7 @@ impl InlineAssistant { let editor_assists = self .assists_by_editor .entry(editor.downgrade()) - .or_insert_with(|| EditorInlineAssists::new(&editor, cx)); + .or_insert_with(|| EditorInlineAssists::new(&editor, window, cx)); let mut assist_group = InlineAssistGroup::new(); for (assist_id, range, prompt_editor, prompt_block_id, end_block_id) in assists { let codegen = prompt_editor.read(cx).codegen().clone(); @@ -429,6 +462,7 @@ impl InlineAssistant { range, codegen, workspace.clone(), + window, cx, ), ); @@ -438,25 +472,26 @@ impl InlineAssistant { self.assist_groups.insert(assist_group_id, assist_group); if let Some(assist_id) = assist_to_focus { - self.focus_assist(assist_id, cx); + self.focus_assist(assist_id, window, cx); } } #[allow(clippy::too_many_arguments)] pub fn suggest_assist( &mut self, - editor: &View, + editor: &Entity, mut range: Range, initial_prompt: String, initial_transaction_id: Option, focus: bool, - workspace: WeakView, - thread_store: Option>, - cx: &mut WindowContext, + workspace: WeakEntity, + thread_store: Option>, + window: &mut Window, + cx: &mut App, ) -> InlineAssistId { let assist_group_id = self.next_assist_group_id.post_inc(); - let prompt_buffer = cx.new_model(|cx| Buffer::local(&initial_prompt, cx)); - let prompt_buffer = cx.new_model(|cx| MultiBuffer::singleton(prompt_buffer, cx)); + let prompt_buffer = cx.new(|cx| Buffer::local(&initial_prompt, cx)); + let prompt_buffer = cx.new(|cx| MultiBuffer::singleton(prompt_buffer, cx)); let assist_id = self.next_assist_id.post_inc(); @@ -467,9 +502,9 @@ impl InlineAssistant { range.end = range.end.bias_right(&snapshot); } - let context_store = cx.new_model(|_cx| ContextStore::new(workspace.clone())); + let context_store = cx.new(|_cx| ContextStore::new(workspace.clone())); - let codegen = cx.new_model(|cx| { + let codegen = cx.new(|cx| { BufferCodegen::new( editor.read(cx).buffer().clone(), range.clone(), @@ -482,7 +517,7 @@ impl InlineAssistant { }); let gutter_dimensions = Arc::new(Mutex::new(GutterDimensions::default())); - let prompt_editor = cx.new_view(|cx| { + let prompt_editor = cx.new(|cx| { PromptEditor::new_buffer( assist_id, gutter_dimensions.clone(), @@ -493,6 +528,7 @@ impl InlineAssistant { context_store, workspace.clone(), thread_store, + window, cx, ) }); @@ -503,7 +539,7 @@ impl InlineAssistant { let editor_assists = self .assists_by_editor .entry(editor.downgrade()) - .or_insert_with(|| EditorInlineAssists::new(&editor, cx)); + .or_insert_with(|| EditorInlineAssists::new(&editor, window, cx)); let mut assist_group = InlineAssistGroup::new(); self.assists.insert( @@ -518,6 +554,7 @@ impl InlineAssistant { range, codegen.clone(), workspace.clone(), + window, cx, ), ); @@ -526,7 +563,7 @@ impl InlineAssistant { self.assist_groups.insert(assist_group_id, assist_group); if focus { - self.focus_assist(assist_id, cx); + self.focus_assist(assist_id, window, cx); } assist_id @@ -534,10 +571,10 @@ impl InlineAssistant { fn insert_assist_blocks( &self, - editor: &View, + editor: &Entity, range: &Range, - prompt_editor: &View>, - cx: &mut WindowContext, + prompt_editor: &Entity>, + cx: &mut App, ) -> [CustomBlockId; 2] { let prompt_editor_height = prompt_editor.update(cx, |prompt_editor, cx| { prompt_editor @@ -574,7 +611,7 @@ impl InlineAssistant { }) } - fn handle_prompt_editor_focus_in(&mut self, assist_id: InlineAssistId, cx: &mut WindowContext) { + fn handle_prompt_editor_focus_in(&mut self, assist_id: InlineAssistId, cx: &mut App) { let assist = &self.assists[&assist_id]; let Some(decorations) = assist.decorations.as_ref() else { return; @@ -615,11 +652,7 @@ impl InlineAssistant { .ok(); } - fn handle_prompt_editor_focus_out( - &mut self, - assist_id: InlineAssistId, - cx: &mut WindowContext, - ) { + fn handle_prompt_editor_focus_out(&mut self, assist_id: InlineAssistId, cx: &mut App) { let assist = &self.assists[&assist_id]; let assist_group = self.assist_groups.get_mut(&assist.group_id).unwrap(); if assist_group.active_assist_id == Some(assist_id) { @@ -638,26 +671,27 @@ impl InlineAssistant { fn handle_prompt_editor_event( &mut self, - prompt_editor: View>, + prompt_editor: Entity>, event: &PromptEditorEvent, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { let assist_id = prompt_editor.read(cx).id(); match event { PromptEditorEvent::StartRequested => { - self.start_assist(assist_id, cx); + self.start_assist(assist_id, window, cx); } PromptEditorEvent::StopRequested => { self.stop_assist(assist_id, cx); } PromptEditorEvent::ConfirmRequested { execute: _ } => { - self.finish_assist(assist_id, false, cx); + self.finish_assist(assist_id, false, window, cx); } PromptEditorEvent::CancelRequested => { - self.finish_assist(assist_id, true, cx); + self.finish_assist(assist_id, true, window, cx); } PromptEditorEvent::DismissRequested => { - self.dismiss_assist(assist_id, cx); + self.dismiss_assist(assist_id, window, cx); } PromptEditorEvent::Resized { .. } => { // This only matters for the terminal inline assistant @@ -665,7 +699,7 @@ impl InlineAssistant { } } - fn handle_editor_newline(&mut self, editor: View, cx: &mut WindowContext) { + fn handle_editor_newline(&mut self, editor: Entity, window: &mut Window, cx: &mut App) { let Some(editor_assists) = self.assists_by_editor.get(&editor.downgrade()) else { return; }; @@ -683,9 +717,9 @@ impl InlineAssistant { if assist_range.contains(&selection.start) && assist_range.contains(&selection.end) { if matches!(assist.codegen.read(cx).status(cx), CodegenStatus::Pending) { - self.dismiss_assist(*assist_id, cx); + self.dismiss_assist(*assist_id, window, cx); } else { - self.finish_assist(*assist_id, false, cx); + self.finish_assist(*assist_id, false, window, cx); } return; @@ -696,7 +730,7 @@ impl InlineAssistant { cx.propagate(); } - fn handle_editor_cancel(&mut self, editor: View, cx: &mut WindowContext) { + fn handle_editor_cancel(&mut self, editor: Entity, window: &mut Window, cx: &mut App) { let Some(editor_assists) = self.assists_by_editor.get(&editor.downgrade()) else { return; }; @@ -716,7 +750,7 @@ impl InlineAssistant { if assist_range.contains(&selection.start) && assist_range.contains(&selection.end) { - self.focus_assist(*assist_id, cx); + self.focus_assist(*assist_id, window, cx); return; } else { let distance_from_selection = assist_range @@ -743,22 +777,27 @@ impl InlineAssistant { } if let Some((&assist_id, _)) = closest_assist_fallback { - self.focus_assist(assist_id, cx); + self.focus_assist(assist_id, window, cx); } } cx.propagate(); } - fn handle_editor_release(&mut self, editor: WeakView, cx: &mut WindowContext) { + fn handle_editor_release( + &mut self, + editor: WeakEntity, + window: &mut Window, + cx: &mut App, + ) { if let Some(editor_assists) = self.assists_by_editor.get_mut(&editor) { for assist_id in editor_assists.assist_ids.clone() { - self.finish_assist(assist_id, true, cx); + self.finish_assist(assist_id, true, window, cx); } } } - fn handle_editor_change(&mut self, editor: View, cx: &mut WindowContext) { + fn handle_editor_change(&mut self, editor: Entity, window: &mut Window, cx: &mut App) { let Some(editor_assists) = self.assists_by_editor.get(&editor.downgrade()) else { return; }; @@ -778,16 +817,17 @@ impl InlineAssistant { .0 as f32 - scroll_lock.distance_from_top; if target_scroll_top != scroll_position.y { - editor.set_scroll_position(point(scroll_position.x, target_scroll_top), cx); + editor.set_scroll_position(point(scroll_position.x, target_scroll_top), window, cx); } }); } fn handle_editor_event( &mut self, - editor: View, + editor: Entity, event: &EditorEvent, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { let Some(editor_assists) = self.assists_by_editor.get_mut(&editor.downgrade()) else { return; @@ -811,7 +851,7 @@ impl InlineAssistant { .iter() .any(|range| range.overlaps(&assist_range)) { - self.finish_assist(assist_id, false, cx); + self.finish_assist(assist_id, false, window, cx); } } } @@ -839,7 +879,11 @@ impl InlineAssistant { for assist_id in editor_assists.assist_ids.clone() { let assist = &self.assists[&assist_id]; if let Some(decorations) = assist.decorations.as_ref() { - if decorations.prompt_editor.focus_handle(cx).is_focused(cx) { + if decorations + .prompt_editor + .focus_handle(cx) + .is_focused(window) + { return; } } @@ -851,18 +895,24 @@ impl InlineAssistant { } } - pub fn finish_assist(&mut self, assist_id: InlineAssistId, undo: bool, cx: &mut WindowContext) { + pub fn finish_assist( + &mut self, + assist_id: InlineAssistId, + undo: bool, + window: &mut Window, + cx: &mut App, + ) { if let Some(assist) = self.assists.get(&assist_id) { let assist_group_id = assist.group_id; if self.assist_groups[&assist_group_id].linked { - for assist_id in self.unlink_assist_group(assist_group_id, cx) { - self.finish_assist(assist_id, undo, cx); + for assist_id in self.unlink_assist_group(assist_group_id, window, cx) { + self.finish_assist(assist_id, undo, window, cx); } return; } } - self.dismiss_assist(assist_id, cx); + self.dismiss_assist(assist_id, window, cx); if let Some(assist) = self.assists.remove(&assist_id) { if let hash_map::Entry::Occupied(mut entry) = self.assist_groups.entry(assist.group_id) @@ -931,7 +981,12 @@ impl InlineAssistant { } } - fn dismiss_assist(&mut self, assist_id: InlineAssistId, cx: &mut WindowContext) -> bool { + fn dismiss_assist( + &mut self, + assist_id: InlineAssistId, + window: &mut Window, + cx: &mut App, + ) -> bool { let Some(assist) = self.assists.get_mut(&assist_id) else { return false; }; @@ -952,9 +1007,9 @@ impl InlineAssistant { if decorations .prompt_editor .focus_handle(cx) - .contains_focused(cx) + .contains_focused(window, cx) { - self.focus_next_assist(assist_id, cx); + self.focus_next_assist(assist_id, window, cx); } if let Some(editor_assists) = self.assists_by_editor.get_mut(&editor.downgrade()) { @@ -971,7 +1026,7 @@ impl InlineAssistant { true } - fn focus_next_assist(&mut self, assist_id: InlineAssistId, cx: &mut WindowContext) { + fn focus_next_assist(&mut self, assist_id: InlineAssistId, window: &mut Window, cx: &mut App) { let Some(assist) = self.assists.get(&assist_id) else { return; }; @@ -991,15 +1046,18 @@ impl InlineAssistant { for assist_id in assist_ids { let assist = &self.assists[assist_id]; if assist.decorations.is_some() { - self.focus_assist(*assist_id, cx); + self.focus_assist(*assist_id, window, cx); return; } } - assist.editor.update(cx, |editor, cx| editor.focus(cx)).ok(); + assist + .editor + .update(cx, |editor, cx| window.focus(&editor.focus_handle(cx))) + .ok(); } - fn focus_assist(&mut self, assist_id: InlineAssistId, cx: &mut WindowContext) { + fn focus_assist(&mut self, assist_id: InlineAssistId, window: &mut Window, cx: &mut App) { let Some(assist) = self.assists.get(&assist_id) else { return; }; @@ -1007,16 +1065,21 @@ impl InlineAssistant { if let Some(decorations) = assist.decorations.as_ref() { decorations.prompt_editor.update(cx, |prompt_editor, cx| { prompt_editor.editor.update(cx, |editor, cx| { - editor.focus(cx); - editor.select_all(&SelectAll, cx); + window.focus(&editor.focus_handle(cx)); + editor.select_all(&SelectAll, window, cx); }) }); } - self.scroll_to_assist(assist_id, cx); + self.scroll_to_assist(assist_id, window, cx); } - pub fn scroll_to_assist(&mut self, assist_id: InlineAssistId, cx: &mut WindowContext) { + pub fn scroll_to_assist( + &mut self, + assist_id: InlineAssistId, + window: &mut Window, + cx: &mut App, + ) { let Some(assist) = self.assists.get(&assist_id) else { return; }; @@ -1026,7 +1089,7 @@ impl InlineAssistant { let position = assist.range.start; editor.update(cx, |editor, cx| { - editor.change_selections(None, cx, |selections| { + editor.change_selections(None, window, cx, |selections| { selections.select_anchor_ranges([position..position]) }); @@ -1042,7 +1105,7 @@ impl InlineAssistant { .unwrap() .0 as f32; } else { - let snapshot = editor.snapshot(cx); + let snapshot = editor.snapshot(window, cx); let start_row = assist .range .start @@ -1059,13 +1122,16 @@ impl InlineAssistant { let scroll_bottom = scroll_top + height_in_lines; if scroll_target_top < scroll_top { - editor.set_scroll_position(point(0., scroll_target_top), cx); + editor.set_scroll_position(point(0., scroll_target_top), window, cx); } else if scroll_target_bottom > scroll_bottom { if (scroll_target_bottom - scroll_target_top) <= height_in_lines { - editor - .set_scroll_position(point(0., scroll_target_bottom - height_in_lines), cx); + editor.set_scroll_position( + point(0., scroll_target_bottom - height_in_lines), + window, + cx, + ); } else { - editor.set_scroll_position(point(0., scroll_target_top), cx); + editor.set_scroll_position(point(0., scroll_target_top), window, cx); } } }); @@ -1074,7 +1140,8 @@ impl InlineAssistant { fn unlink_assist_group( &mut self, assist_group_id: InlineAssistGroupId, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Vec { let assist_group = self.assist_groups.get_mut(&assist_group_id).unwrap(); assist_group.linked = false; @@ -1083,13 +1150,13 @@ impl InlineAssistant { if let Some(editor_decorations) = assist.decorations.as_ref() { editor_decorations .prompt_editor - .update(cx, |prompt_editor, cx| prompt_editor.unlink(cx)); + .update(cx, |prompt_editor, cx| prompt_editor.unlink(window, cx)); } } assist_group.assist_ids.clone() } - pub fn start_assist(&mut self, assist_id: InlineAssistId, cx: &mut WindowContext) { + pub fn start_assist(&mut self, assist_id: InlineAssistId, window: &mut Window, cx: &mut App) { let assist = if let Some(assist) = self.assists.get_mut(&assist_id) { assist } else { @@ -1098,8 +1165,8 @@ impl InlineAssistant { let assist_group_id = assist.group_id; if self.assist_groups[&assist_group_id].linked { - for assist_id in self.unlink_assist_group(assist_group_id, cx) { - self.start_assist(assist_id, cx); + for assist_id in self.unlink_assist_group(assist_group_id, window, cx) { + self.start_assist(assist_id, window, cx); } return; } @@ -1120,7 +1187,7 @@ impl InlineAssistant { .log_err(); } - pub fn stop_assist(&mut self, assist_id: InlineAssistId, cx: &mut WindowContext) { + pub fn stop_assist(&mut self, assist_id: InlineAssistId, cx: &mut App) { let assist = if let Some(assist) = self.assists.get_mut(&assist_id) { assist } else { @@ -1130,7 +1197,7 @@ impl InlineAssistant { assist.codegen.update(cx, |codegen, cx| codegen.stop(cx)); } - fn update_editor_highlights(&self, editor: &View, cx: &mut WindowContext) { + fn update_editor_highlights(&self, editor: &Entity, cx: &mut App) { let mut gutter_pending_ranges = Vec::new(); let mut gutter_transformed_ranges = Vec::new(); let mut foreground_ranges = Vec::new(); @@ -1223,9 +1290,10 @@ impl InlineAssistant { fn update_editor_blocks( &mut self, - editor: &View, + editor: &Entity, assist_id: InlineAssistId, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { let Some(assist) = self.assists.get_mut(&assist_id) else { return; @@ -1255,10 +1323,9 @@ impl InlineAssistant { )) .unwrap(); - let deleted_lines_editor = cx.new_view(|cx| { - let multi_buffer = cx.new_model(|_| { - MultiBuffer::without_headers(language::Capability::ReadOnly) - }); + let deleted_lines_editor = cx.new(|cx| { + let multi_buffer = + cx.new(|_| MultiBuffer::without_headers(language::Capability::ReadOnly)); multi_buffer.update(cx, |multi_buffer, cx| { multi_buffer.push_excerpts( old_buffer.clone(), @@ -1271,14 +1338,14 @@ impl InlineAssistant { }); enum DeletedLines {} - let mut editor = Editor::for_multibuffer(multi_buffer, None, true, cx); + let mut editor = Editor::for_multibuffer(multi_buffer, None, true, window, cx); editor.set_soft_wrap_mode(language::language_settings::SoftWrap::None, cx); editor.set_show_wrap_guides(false, cx); editor.set_show_gutter(false, cx); editor.scroll_manager.set_forbid_vertical_scroll(true); editor.set_show_scrollbars(false, cx); editor.set_read_only(true); - editor.set_show_inline_completions(Some(false), cx); + editor.set_show_inline_completions(Some(false), window, cx); editor.highlight_rows::( Anchor::min()..Anchor::max(), cx.theme().status().deleted_background, @@ -1299,7 +1366,7 @@ impl InlineAssistant { .block_mouse_down() .bg(cx.theme().status().deleted_background) .size_full() - .h(height as f32 * cx.line_height()) + .h(height as f32 * cx.window.line_height()) .pl(cx.gutter_dimensions.full_width()) .child(deleted_lines_editor.clone()) .into_any_element() @@ -1317,13 +1384,14 @@ impl InlineAssistant { fn resolve_inline_assist_target( workspace: &mut Workspace, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Option { if let Some(terminal_panel) = workspace.panel::(cx) { if terminal_panel .read(cx) .focus_handle(cx) - .contains_focused(cx) + .contains_focused(window, cx) { if let Some(terminal_view) = terminal_panel.read(cx).pane().and_then(|pane| { pane.read(cx) @@ -1366,13 +1434,13 @@ struct InlineAssistScrollLock { impl EditorInlineAssists { #[allow(clippy::too_many_arguments)] - fn new(editor: &View, cx: &mut WindowContext) -> Self { + fn new(editor: &Entity, window: &mut Window, cx: &mut App) -> Self { let (highlight_updates_tx, mut highlight_updates_rx) = async_watch::channel(()); Self { assist_ids: Vec::new(), scroll_lock: None, highlight_updates: highlight_updates_tx, - _update_highlights: cx.spawn(|mut cx| { + _update_highlights: cx.spawn(|cx| { let editor = editor.downgrade(); async move { while let Ok(()) = highlight_updates_rx.changed().await { @@ -1385,47 +1453,43 @@ impl EditorInlineAssists { } }), _subscriptions: vec![ - cx.observe_release(editor, { + cx.observe_release_in(editor, window, { let editor = editor.downgrade(); - |_, cx| { + |_, window, cx| { InlineAssistant::update_global(cx, |this, cx| { - this.handle_editor_release(editor, cx); + this.handle_editor_release(editor, window, cx); }) } }), - cx.observe(editor, move |editor, cx| { + window.observe(editor, cx, move |editor, window, cx| { InlineAssistant::update_global(cx, |this, cx| { - this.handle_editor_change(editor, cx) + this.handle_editor_change(editor, window, cx) }) }), - cx.subscribe(editor, move |editor, event, cx| { + window.subscribe(editor, cx, move |editor, event, window, cx| { InlineAssistant::update_global(cx, |this, cx| { - this.handle_editor_event(editor, event, cx) + this.handle_editor_event(editor, event, window, cx) }) }), editor.update(cx, |editor, cx| { - let editor_handle = cx.view().downgrade(); - editor.register_action( - move |_: &editor::actions::Newline, cx: &mut WindowContext| { - InlineAssistant::update_global(cx, |this, cx| { - if let Some(editor) = editor_handle.upgrade() { - this.handle_editor_newline(editor, cx) - } - }) - }, - ) + let editor_handle = cx.model().downgrade(); + editor.register_action(move |_: &editor::actions::Newline, window, cx| { + InlineAssistant::update_global(cx, |this, cx| { + if let Some(editor) = editor_handle.upgrade() { + this.handle_editor_newline(editor, window, cx) + } + }) + }) }), editor.update(cx, |editor, cx| { - let editor_handle = cx.view().downgrade(); - editor.register_action( - move |_: &editor::actions::Cancel, cx: &mut WindowContext| { - InlineAssistant::update_global(cx, |this, cx| { - if let Some(editor) = editor_handle.upgrade() { - this.handle_editor_cancel(editor, cx) - } - }) - }, - ) + let editor_handle = cx.model().downgrade(); + editor.register_action(move |_: &editor::actions::Cancel, window, cx| { + InlineAssistant::update_global(cx, |this, cx| { + if let Some(editor) = editor_handle.upgrade() { + this.handle_editor_cancel(editor, window, cx) + } + }) + }) }), ], } @@ -1448,7 +1512,7 @@ impl InlineAssistGroup { } } -fn build_assist_editor_renderer(editor: &View>) -> RenderBlock { +fn build_assist_editor_renderer(editor: &Entity>) -> RenderBlock { let editor = editor.clone(); Arc::new(move |cx: &mut BlockContext| { @@ -1473,11 +1537,11 @@ impl InlineAssistGroupId { pub struct InlineAssist { group_id: InlineAssistGroupId, range: Range, - editor: WeakView, + editor: WeakEntity, decorations: Option, - codegen: Model, + codegen: Entity, _subscriptions: Vec, - workspace: WeakView, + workspace: WeakEntity, } impl InlineAssist { @@ -1485,14 +1549,15 @@ impl InlineAssist { fn new( assist_id: InlineAssistId, group_id: InlineAssistGroupId, - editor: &View, - prompt_editor: &View>, + editor: &Entity, + prompt_editor: &Entity>, prompt_block_id: CustomBlockId, end_block_id: CustomBlockId, range: Range, - codegen: Model, - workspace: WeakView, - cx: &mut WindowContext, + codegen: Entity, + workspace: WeakEntity, + window: &mut Window, + cx: &mut App, ) -> Self { let prompt_editor_focus_handle = prompt_editor.focus_handle(cx); InlineAssist { @@ -1508,24 +1573,24 @@ impl InlineAssist { codegen: codegen.clone(), workspace: workspace.clone(), _subscriptions: vec![ - cx.on_focus_in(&prompt_editor_focus_handle, move |cx| { + window.on_focus_in(&prompt_editor_focus_handle, cx, move |_, cx| { InlineAssistant::update_global(cx, |this, cx| { this.handle_prompt_editor_focus_in(assist_id, cx) }) }), - cx.on_focus_out(&prompt_editor_focus_handle, move |_, cx| { + window.on_focus_out(&prompt_editor_focus_handle, cx, move |_, _, cx| { InlineAssistant::update_global(cx, |this, cx| { this.handle_prompt_editor_focus_out(assist_id, cx) }) }), - cx.subscribe(prompt_editor, |prompt_editor, event, cx| { + window.subscribe(prompt_editor, cx, |prompt_editor, event, window, cx| { InlineAssistant::update_global(cx, |this, cx| { - this.handle_prompt_editor_event(prompt_editor, event, cx) + this.handle_prompt_editor_event(prompt_editor, event, window, cx) }) }), - cx.observe(&codegen, { + window.observe(&codegen, cx, { let editor = editor.downgrade(); - move |_, cx| { + move |_, window, cx| { if let Some(editor) = editor.upgrade() { InlineAssistant::update_global(cx, |this, cx| { if let Some(editor_assists) = @@ -1534,14 +1599,14 @@ impl InlineAssist { editor_assists.highlight_updates.send(()).ok(); } - this.update_editor_blocks(&editor, assist_id, cx); + this.update_editor_blocks(&editor, assist_id, window, cx); }) } } }), - cx.subscribe(&codegen, move |codegen, event, cx| { + window.subscribe(&codegen, cx, move |codegen, event, window, cx| { InlineAssistant::update_global(cx, |this, cx| match event { - CodegenEvent::Undone => this.finish_assist(assist_id, false, cx), + CodegenEvent::Undone => this.finish_assist(assist_id, false, window, cx), CodegenEvent::Finished => { let assist = if let Some(assist) = this.assists.get(&assist_id) { assist @@ -1568,7 +1633,7 @@ impl InlineAssist { } if assist.decorations.is_none() { - this.finish_assist(assist_id, false, cx); + this.finish_assist(assist_id, false, window, cx); } } }) @@ -1577,7 +1642,7 @@ impl InlineAssist { } } - fn user_prompt(&self, cx: &AppContext) -> Option { + fn user_prompt(&self, cx: &App) -> Option { let decorations = self.decorations.as_ref()?; Some(decorations.prompt_editor.read(cx).prompt(cx)) } @@ -1585,15 +1650,15 @@ impl InlineAssist { struct InlineAssistDecorations { prompt_block_id: CustomBlockId, - prompt_editor: View>, + prompt_editor: Entity>, removed_line_block_ids: HashSet, end_block_id: CustomBlockId, } struct AssistantCodeActionProvider { - editor: WeakView, - workspace: WeakView, - thread_store: Option>, + editor: WeakEntity, + workspace: WeakEntity, + thread_store: Option>, } const ASSISTANT_CODE_ACTION_PROVIDER_ID: &str = "assistant2"; @@ -1605,9 +1670,10 @@ impl CodeActionProvider for AssistantCodeActionProvider { fn code_actions( &self, - buffer: &Model, + buffer: &Entity, range: Range, - cx: &mut WindowContext, + _: &mut Window, + cx: &mut App, ) -> Task>> { if !AssistantSettings::get_global(cx).enabled { return Task::ready(Ok(Vec::new())); @@ -1656,16 +1722,17 @@ impl CodeActionProvider for AssistantCodeActionProvider { fn apply_code_action( &self, - buffer: Model, + buffer: Entity, action: CodeAction, excerpt_id: ExcerptId, _push_to_history: bool, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Task> { let editor = self.editor.clone(); let workspace = self.workspace.clone(); let thread_store = self.thread_store.clone(); - cx.spawn(|mut cx| async move { + window.spawn(cx, |mut cx| async move { let editor = editor.upgrade().context("editor was released")?; let range = editor .update(&mut cx, |editor, cx| { @@ -1704,7 +1771,7 @@ impl CodeActionProvider for AssistantCodeActionProvider { })? .context("invalid range")?; - cx.update_global(|assistant: &mut InlineAssistant, cx| { + cx.update_global(|assistant: &mut InlineAssistant, window, cx| { let assist_id = assistant.suggest_assist( &editor, range, @@ -1713,9 +1780,10 @@ impl CodeActionProvider for AssistantCodeActionProvider { true, workspace, thread_store, + window, cx, ); - assistant.start_assist(assist_id, cx); + assistant.start_assist(assist_id, window, cx); })?; Ok(ProjectTransaction::default()) diff --git a/crates/assistant2/src/inline_prompt_editor.rs b/crates/assistant2/src/inline_prompt_editor.rs index 1818e9e3cc..dd1c703e2a 100644 --- a/crates/assistant2/src/inline_prompt_editor.rs +++ b/crates/assistant2/src/inline_prompt_editor.rs @@ -16,9 +16,8 @@ use editor::{ use feature_flags::{FeatureFlagAppExt as _, ZedPro}; use fs::Fs; use gpui::{ - anchored, deferred, point, AnyElement, AppContext, ClickEvent, CursorStyle, EventEmitter, - FocusHandle, FocusableView, FontWeight, Model, Subscription, TextStyle, View, ViewContext, - WeakModel, WeakView, WindowContext, + anchored, deferred, point, AnyElement, App, ClickEvent, Context, CursorStyle, Entity, + EventEmitter, FocusHandle, Focusable, FontWeight, Subscription, TextStyle, WeakEntity, Window, }; use language_model::{LanguageModel, LanguageModelRegistry}; use language_model_selector::LanguageModelSelector; @@ -35,12 +34,12 @@ use util::ResultExt; use workspace::Workspace; pub struct PromptEditor { - pub editor: View, + pub editor: Entity, mode: PromptEditorMode, - context_store: Model, - context_strip: View, + context_store: Entity, + context_strip: Entity, context_picker_menu_handle: PopoverMenuHandle, - model_selector: View, + model_selector: Entity, model_selector_menu_handle: PopoverMenuHandle, edited_since_done: bool, prompt_history: VecDeque, @@ -56,7 +55,7 @@ pub struct PromptEditor { impl EventEmitter for PromptEditor {} impl Render for PromptEditor { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { let ui_font_size = ThemeSettings::get_global(cx).ui_font_size; let mut buttons = Vec::new(); @@ -87,7 +86,7 @@ impl Render for PromptEditor { PromptEditorMode::Terminal { .. } => Pixels::from(8.0), }; - buttons.extend(self.render_buttons(cx)); + buttons.extend(self.render_buttons(window, cx)); v_flex() .key_context("PromptEditor") @@ -163,9 +162,7 @@ impl Render for PromptEditor { el.child( div() .id("error") - .tooltip(move |cx| { - Tooltip::text(error_message.clone(), cx) - }) + .tooltip(Tooltip::text(error_message)) .child( Icon::new(IconName::XCircle) .size(IconSize::Small) @@ -179,7 +176,7 @@ impl Render for PromptEditor { h_flex() .w_full() .justify_between() - .child(div().flex_1().child(self.render_editor(cx))) + .child(div().flex_1().child(self.render_editor(window, cx))) .child( WithRemSize::new(ui_font_size) .flex() @@ -209,8 +206,8 @@ impl Render for PromptEditor { } } -impl FocusableView for PromptEditor { - fn focus_handle(&self, cx: &AppContext) -> FocusHandle { +impl Focusable for PromptEditor { + fn focus_handle(&self, cx: &App) -> FocusHandle { self.editor.focus_handle(cx) } } @@ -218,47 +215,50 @@ impl FocusableView for PromptEditor { impl PromptEditor { const MAX_LINES: u8 = 8; - fn codegen_status<'a>(&'a self, cx: &'a AppContext) -> &'a CodegenStatus { + fn codegen_status<'a>(&'a self, cx: &'a App) -> &'a CodegenStatus { match &self.mode { PromptEditorMode::Buffer { codegen, .. } => codegen.read(cx).status(cx), PromptEditorMode::Terminal { codegen, .. } => &codegen.read(cx).status, } } - fn subscribe_to_editor(&mut self, cx: &mut ViewContext) { + fn subscribe_to_editor(&mut self, window: &mut Window, cx: &mut Context) { self.editor_subscriptions.clear(); - self.editor_subscriptions - .push(cx.subscribe(&self.editor, Self::handle_prompt_editor_events)); + self.editor_subscriptions.push(cx.subscribe_in( + &self.editor, + window, + Self::handle_prompt_editor_events, + )); } pub fn set_show_cursor_when_unfocused( &mut self, show_cursor_when_unfocused: bool, - cx: &mut ViewContext, + cx: &mut Context, ) { self.editor.update(cx, |editor, cx| { editor.set_show_cursor_when_unfocused(show_cursor_when_unfocused, cx) }); } - pub fn unlink(&mut self, cx: &mut ViewContext) { + pub fn unlink(&mut self, window: &mut Window, cx: &mut Context) { let prompt = self.prompt(cx); - let focus = self.editor.focus_handle(cx).contains_focused(cx); - self.editor = cx.new_view(|cx| { - let mut editor = Editor::auto_height(Self::MAX_LINES as usize, cx); + let focus = self.editor.focus_handle(cx).contains_focused(window, cx); + self.editor = cx.new(|cx| { + let mut editor = Editor::auto_height(Self::MAX_LINES as usize, window, cx); editor.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx); - editor.set_placeholder_text(Self::placeholder_text(&self.mode, cx), cx); + editor.set_placeholder_text(Self::placeholder_text(&self.mode, window, cx), cx); editor.set_placeholder_text("Add a prompt…", cx); - editor.set_text(prompt, cx); + editor.set_text(prompt, window, cx); if focus { - editor.focus(cx); + window.focus(&editor.focus_handle(cx)); } editor }); - self.subscribe_to_editor(cx); + self.subscribe_to_editor(window, cx); } - pub fn placeholder_text(mode: &PromptEditorMode, cx: &WindowContext) -> String { + pub fn placeholder_text(mode: &PromptEditorMode, window: &mut Window, cx: &mut App) -> String { let action = match mode { PromptEditorMode::Buffer { codegen, .. } => { if codegen.read(cx).is_insertion { @@ -271,36 +271,42 @@ impl PromptEditor { }; let assistant_panel_keybinding = - ui::text_for_action(&zed_actions::assistant::ToggleFocus, cx) + ui::text_for_action(&zed_actions::assistant::ToggleFocus, window) .map(|keybinding| format!("{keybinding} to chat ― ")) .unwrap_or_default(); format!("{action}… ({assistant_panel_keybinding}↓↑ for history)") } - pub fn prompt(&self, cx: &AppContext) -> String { + pub fn prompt(&self, cx: &App) -> String { self.editor.read(cx).text(cx) } - fn toggle_rate_limit_notice(&mut self, _: &ClickEvent, cx: &mut ViewContext) { + fn toggle_rate_limit_notice( + &mut self, + _: &ClickEvent, + window: &mut Window, + cx: &mut Context, + ) { self.show_rate_limit_notice = !self.show_rate_limit_notice; if self.show_rate_limit_notice { - cx.focus_view(&self.editor); + window.focus(&self.editor.focus_handle(cx)); } cx.notify(); } fn handle_prompt_editor_events( &mut self, - _: View, + _: &Entity, event: &EditorEvent, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { match event { EditorEvent::Edited { .. } => { - if let Some(workspace) = cx.window_handle().downcast::() { + if let Some(workspace) = window.window_handle().downcast::() { workspace - .update(cx, |workspace, cx| { + .update(cx, |workspace, _, cx| { let is_via_ssh = workspace .project() .update(cx, |project, _| project.is_via_ssh()); @@ -334,20 +340,40 @@ impl PromptEditor { } } - fn toggle_context_picker(&mut self, _: &ToggleContextPicker, cx: &mut ViewContext) { - self.context_picker_menu_handle.toggle(cx); + fn toggle_context_picker( + &mut self, + _: &ToggleContextPicker, + window: &mut Window, + cx: &mut Context, + ) { + self.context_picker_menu_handle.toggle(window, cx); } - fn toggle_model_selector(&mut self, _: &ToggleModelSelector, cx: &mut ViewContext) { - self.model_selector_menu_handle.toggle(cx); + fn toggle_model_selector( + &mut self, + _: &ToggleModelSelector, + window: &mut Window, + cx: &mut Context, + ) { + self.model_selector_menu_handle.toggle(window, cx); } - pub fn remove_all_context(&mut self, _: &RemoveAllContext, cx: &mut ViewContext) { + pub fn remove_all_context( + &mut self, + _: &RemoveAllContext, + _window: &mut Window, + cx: &mut Context, + ) { self.context_store.update(cx, |store, _cx| store.clear()); cx.notify(); } - fn cancel(&mut self, _: &editor::actions::Cancel, cx: &mut ViewContext) { + fn cancel( + &mut self, + _: &editor::actions::Cancel, + _window: &mut Window, + cx: &mut Context, + ) { match self.codegen_status(cx) { CodegenStatus::Idle | CodegenStatus::Done | CodegenStatus::Error(_) => { cx.emit(PromptEditorEvent::CancelRequested); @@ -358,7 +384,7 @@ impl PromptEditor { } } - fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext) { + fn confirm(&mut self, _: &menu::Confirm, _window: &mut Window, cx: &mut Context) { match self.codegen_status(cx) { CodegenStatus::Idle => { cx.emit(PromptEditorEvent::StartRequested); @@ -379,49 +405,49 @@ impl PromptEditor { } } - fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext) { + fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context) { if let Some(ix) = self.prompt_history_ix { if ix > 0 { self.prompt_history_ix = Some(ix - 1); let prompt = self.prompt_history[ix - 1].as_str(); self.editor.update(cx, |editor, cx| { - editor.set_text(prompt, cx); - editor.move_to_beginning(&Default::default(), cx); + editor.set_text(prompt, window, cx); + editor.move_to_beginning(&Default::default(), window, cx); }); } } else if !self.prompt_history.is_empty() { self.prompt_history_ix = Some(self.prompt_history.len() - 1); let prompt = self.prompt_history[self.prompt_history.len() - 1].as_str(); self.editor.update(cx, |editor, cx| { - editor.set_text(prompt, cx); - editor.move_to_beginning(&Default::default(), cx); + editor.set_text(prompt, window, cx); + editor.move_to_beginning(&Default::default(), window, cx); }); } } - fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext) { + fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context) { if let Some(ix) = self.prompt_history_ix { if ix < self.prompt_history.len() - 1 { self.prompt_history_ix = Some(ix + 1); let prompt = self.prompt_history[ix + 1].as_str(); self.editor.update(cx, |editor, cx| { - editor.set_text(prompt, cx); - editor.move_to_end(&Default::default(), cx) + editor.set_text(prompt, window, cx); + editor.move_to_end(&Default::default(), window, cx) }); } else { self.prompt_history_ix = None; let prompt = self.pending_prompt.as_str(); self.editor.update(cx, |editor, cx| { - editor.set_text(prompt, cx); - editor.move_to_end(&Default::default(), cx) + editor.set_text(prompt, window, cx); + editor.move_to_end(&Default::default(), window, cx) }); } } else { - cx.focus_view(&self.context_strip); + self.context_strip.focus_handle(cx).focus(window); } } - fn render_buttons(&self, cx: &mut ViewContext) -> Vec { + fn render_buttons(&self, _window: &mut Window, cx: &mut Context) -> Vec { let mode = match &self.mode { PromptEditorMode::Buffer { codegen, .. } => { let codegen = codegen.read(cx); @@ -443,21 +469,22 @@ impl PromptEditor { .icon(IconName::Return) .icon_size(IconSize::XSmall) .icon_color(Color::Muted) - .on_click(cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::StartRequested))) + .on_click(cx.listener(|_, _, _, cx| cx.emit(PromptEditorEvent::StartRequested))) .into_any_element()] } CodegenStatus::Pending => vec![IconButton::new("stop", IconName::Stop) .icon_color(Color::Error) .shape(IconButtonShape::Square) - .tooltip(move |cx| { + .tooltip(move |window, cx| { Tooltip::with_meta( mode.tooltip_interrupt(), Some(&menu::Cancel), "Changes won't be discarded", + window, cx, ) }) - .on_click(cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::StopRequested))) + .on_click(cx.listener(|_, _, _, cx| cx.emit(PromptEditorEvent::StopRequested))) .into_any_element()], CodegenStatus::Done | CodegenStatus::Error(_) => { let has_error = matches!(codegen_status, CodegenStatus::Error(_)); @@ -465,15 +492,16 @@ impl PromptEditor { vec![IconButton::new("restart", IconName::RotateCw) .icon_color(Color::Info) .shape(IconButtonShape::Square) - .tooltip(move |cx| { + .tooltip(move |window, cx| { Tooltip::with_meta( mode.tooltip_restart(), Some(&menu::Confirm), "Changes will be discarded", + window, cx, ) }) - .on_click(cx.listener(|_, _, cx| { + .on_click(cx.listener(|_, _, _, cx| { cx.emit(PromptEditorEvent::StartRequested); })) .into_any_element()] @@ -481,10 +509,10 @@ impl PromptEditor { let accept = IconButton::new("accept", IconName::Check) .icon_color(Color::Info) .shape(IconButtonShape::Square) - .tooltip(move |cx| { - Tooltip::for_action(mode.tooltip_accept(), &menu::Confirm, cx) + .tooltip(move |window, cx| { + Tooltip::for_action(mode.tooltip_accept(), &menu::Confirm, window, cx) }) - .on_click(cx.listener(|_, _, cx| { + .on_click(cx.listener(|_, _, _, cx| { cx.emit(PromptEditorEvent::ConfirmRequested { execute: false }); })) .into_any_element(); @@ -495,14 +523,15 @@ impl PromptEditor { IconButton::new("confirm", IconName::Play) .icon_color(Color::Info) .shape(IconButtonShape::Square) - .tooltip(|cx| { + .tooltip(|window, cx| { Tooltip::for_action( "Execute Generated Command", &menu::SecondaryConfirm, + window, cx, ) }) - .on_click(cx.listener(|_, _, cx| { + .on_click(cx.listener(|_, _, _, cx| { cx.emit(PromptEditorEvent::ConfirmRequested { execute: true }); })) .into_any_element(), @@ -514,7 +543,12 @@ impl PromptEditor { } } - fn cycle_prev(&mut self, _: &CyclePreviousInlineAssist, cx: &mut ViewContext) { + fn cycle_prev( + &mut self, + _: &CyclePreviousInlineAssist, + _: &mut Window, + cx: &mut Context, + ) { match &self.mode { PromptEditorMode::Buffer { codegen, .. } => { codegen.update(cx, |codegen, cx| codegen.cycle_prev(cx)); @@ -525,7 +559,7 @@ impl PromptEditor { } } - fn cycle_next(&mut self, _: &CycleNextInlineAssist, cx: &mut ViewContext) { + fn cycle_next(&mut self, _: &CycleNextInlineAssist, _: &mut Window, cx: &mut Context) { match &self.mode { PromptEditorMode::Buffer { codegen, .. } => { codegen.update(cx, |codegen, cx| codegen.cycle_next(cx)); @@ -536,16 +570,16 @@ impl PromptEditor { } } - fn render_close_button(&self, cx: &ViewContext) -> AnyElement { + fn render_close_button(&self, cx: &mut Context) -> AnyElement { IconButton::new("cancel", IconName::Close) .icon_color(Color::Muted) .shape(IconButtonShape::Square) - .tooltip(|cx| Tooltip::text("Close Assistant", cx)) - .on_click(cx.listener(|_, _, cx| cx.emit(PromptEditorEvent::CancelRequested))) + .tooltip(Tooltip::text("Close Assistant")) + .on_click(cx.listener(|_, _, _, cx| cx.emit(PromptEditorEvent::CancelRequested))) .into_any_element() } - fn render_cycle_controls(&self, codegen: &BufferCodegen, cx: &ViewContext) -> AnyElement { + fn render_cycle_controls(&self, codegen: &BufferCodegen, cx: &Context) -> AnyElement { let disabled = matches!(codegen.status(cx), CodegenStatus::Idle); let model_registry = LanguageModelRegistry::read_global(cx); @@ -585,13 +619,13 @@ impl PromptEditor { .shape(IconButtonShape::Square) .tooltip({ let focus_handle = self.editor.focus_handle(cx); - move |cx| { - cx.new_view(|cx| { + move |window, cx| { + cx.new(|_| { let mut tooltip = Tooltip::new("Previous Alternative").key_binding( KeyBinding::for_action_in( &CyclePreviousInlineAssist, &focus_handle, - cx, + window, ), ); if !disabled && current_index != 0 { @@ -602,8 +636,8 @@ impl PromptEditor { .into() } }) - .on_click(cx.listener(|this, _, cx| { - this.cycle_prev(&CyclePreviousInlineAssist, cx); + .on_click(cx.listener(|this, _, window, cx| { + this.cycle_prev(&CyclePreviousInlineAssist, window, cx); })), ) .child( @@ -626,13 +660,13 @@ impl PromptEditor { .shape(IconButtonShape::Square) .tooltip({ let focus_handle = self.editor.focus_handle(cx); - move |cx| { - cx.new_view(|cx| { + move |window, cx| { + cx.new(|_| { let mut tooltip = Tooltip::new("Next Alternative").key_binding( KeyBinding::for_action_in( &CycleNextInlineAssist, &focus_handle, - cx, + window, ), ); if !disabled && current_index != total_models - 1 { @@ -643,14 +677,14 @@ impl PromptEditor { .into() } }) - .on_click( - cx.listener(|this, _, cx| this.cycle_next(&CycleNextInlineAssist, cx)), - ), + .on_click(cx.listener(|this, _, window, cx| { + this.cycle_next(&CycleNextInlineAssist, window, cx) + })), ) .into_any_element() } - fn render_rate_limit_notice(&self, cx: &mut ViewContext) -> impl IntoElement { + fn render_rate_limit_notice(&self, cx: &mut Context) -> impl IntoElement { Popover::new().child( v_flex() .occlude() @@ -674,7 +708,7 @@ impl PromptEditor { } else { ui::ToggleState::Unselected }, - |selection, cx| { + |selection, _, cx| { let is_dismissed = match selection { ui::ToggleState::Unselected => false, ui::ToggleState::Indeterminate => return, @@ -693,10 +727,11 @@ impl PromptEditor { .on_click(cx.listener(Self::toggle_rate_limit_notice)), ) .child(Button::new("more-info", "More Info").on_click( - |_event, cx| { - cx.dispatch_action(Box::new( - zed_actions::OpenAccountSettings, - )) + |_event, window, cx| { + window.dispatch_action( + Box::new(zed_actions::OpenAccountSettings), + cx, + ) }, )), ), @@ -704,9 +739,9 @@ impl PromptEditor { ) } - fn render_editor(&mut self, cx: &mut ViewContext) -> AnyElement { + fn render_editor(&mut self, window: &mut Window, cx: &mut Context) -> AnyElement { let font_size = TextSize::Default.rems(cx); - let line_height = font_size.to_pixels(cx.rem_size()) * 1.3; + let line_height = font_size.to_pixels(window.rem_size()) * 1.3; div() .key_context("InlineAssistEditor") @@ -740,17 +775,15 @@ impl PromptEditor { fn handle_context_strip_event( &mut self, - _context_strip: View, + _context_strip: &Entity, event: &ContextStripEvent, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { match event { ContextStripEvent::PickerDismissed | ContextStripEvent::BlurredEmpty - | ContextStripEvent::BlurredUp => { - let editor_focus_handle = self.editor.focus_handle(cx); - cx.focus(&editor_focus_handle); - } + | ContextStripEvent::BlurredUp => self.editor.focus_handle(cx).focus(window), ContextStripEvent::BlurredDown => {} } } @@ -759,12 +792,12 @@ impl PromptEditor { pub enum PromptEditorMode { Buffer { id: InlineAssistId, - codegen: Model, + codegen: Entity, gutter_dimensions: Arc>, }, Terminal { id: TerminalInlineAssistId, - codegen: Model, + codegen: Entity, height_in_lines: u8, }, } @@ -795,13 +828,14 @@ impl PromptEditor { id: InlineAssistId, gutter_dimensions: Arc>, prompt_history: VecDeque, - prompt_buffer: Model, - codegen: Model, + prompt_buffer: Entity, + codegen: Entity, fs: Arc, - context_store: Model, - workspace: WeakView, - thread_store: Option>, - cx: &mut ViewContext>, + context_store: Entity, + workspace: WeakEntity, + thread_store: Option>, + window: &mut Window, + cx: &mut Context>, ) -> PromptEditor { let codegen_subscription = cx.observe(&codegen, Self::handle_codegen_changed); let mode = PromptEditorMode::Buffer { @@ -810,7 +844,7 @@ impl PromptEditor { gutter_dimensions, }; - let prompt_editor = cx.new_view(|cx| { + let prompt_editor = cx.new(|cx| { let mut editor = Editor::new( EditorMode::AutoHeight { max_lines: Self::MAX_LINES as usize, @@ -818,6 +852,7 @@ impl PromptEditor { prompt_buffer, None, false, + window, cx, ); editor.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx); @@ -825,13 +860,13 @@ impl PromptEditor { // always show the cursor (even when it isn't focused) because // typing in one will make what you typed appear in all of them. editor.set_show_cursor_when_unfocused(true, cx); - editor.set_placeholder_text(Self::placeholder_text(&mode, cx), cx); + editor.set_placeholder_text(Self::placeholder_text(&mode, window, cx), cx); editor }); let context_picker_menu_handle = PopoverMenuHandle::default(); let model_selector_menu_handle = PopoverMenuHandle::default(); - let context_strip = cx.new_view(|cx| { + let context_strip = cx.new(|cx| { ContextStrip::new( context_store.clone(), workspace.clone(), @@ -839,23 +874,25 @@ impl PromptEditor { thread_store.clone(), context_picker_menu_handle.clone(), SuggestContextKind::Thread, + window, cx, ) }); let context_strip_subscription = - cx.subscribe(&context_strip, Self::handle_context_strip_event); + cx.subscribe_in(&context_strip, window, Self::handle_context_strip_event); let mut this: PromptEditor = PromptEditor { editor: prompt_editor.clone(), context_store, context_strip, context_picker_menu_handle, - model_selector: cx.new_view(|cx| { + model_selector: cx.new(|cx| { AssistantModelSelector::new( fs, model_selector_menu_handle.clone(), prompt_editor.focus_handle(cx), + window, cx, ) }), @@ -872,14 +909,14 @@ impl PromptEditor { _phantom: Default::default(), }; - this.subscribe_to_editor(cx); + this.subscribe_to_editor(window, cx); this } fn handle_codegen_changed( &mut self, - _: Model, - cx: &mut ViewContext>, + _: Entity, + cx: &mut Context>, ) { match self.codegen_status(cx) { CodegenStatus::Idle => { @@ -918,7 +955,7 @@ impl PromptEditor { } } - pub fn codegen(&self) -> &Model { + pub fn codegen(&self) -> &Entity { match &self.mode { PromptEditorMode::Buffer { codegen, .. } => codegen, PromptEditorMode::Terminal { .. } => unreachable!(), @@ -951,13 +988,14 @@ impl PromptEditor { pub fn new_terminal( id: TerminalInlineAssistId, prompt_history: VecDeque, - prompt_buffer: Model, - codegen: Model, + prompt_buffer: Entity, + codegen: Entity, fs: Arc, - context_store: Model, - workspace: WeakView, - thread_store: Option>, - cx: &mut ViewContext, + context_store: Entity, + workspace: WeakEntity, + thread_store: Option>, + window: &mut Window, + cx: &mut Context, ) -> Self { let codegen_subscription = cx.observe(&codegen, Self::handle_codegen_changed); let mode = PromptEditorMode::Terminal { @@ -966,7 +1004,7 @@ impl PromptEditor { height_in_lines: 1, }; - let prompt_editor = cx.new_view(|cx| { + let prompt_editor = cx.new(|cx| { let mut editor = Editor::new( EditorMode::AutoHeight { max_lines: Self::MAX_LINES as usize, @@ -974,16 +1012,17 @@ impl PromptEditor { prompt_buffer, None, false, + window, cx, ); editor.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx); - editor.set_placeholder_text(Self::placeholder_text(&mode, cx), cx); + editor.set_placeholder_text(Self::placeholder_text(&mode, window, cx), cx); editor }); let context_picker_menu_handle = PopoverMenuHandle::default(); let model_selector_menu_handle = PopoverMenuHandle::default(); - let context_strip = cx.new_view(|cx| { + let context_strip = cx.new(|cx| { ContextStrip::new( context_store.clone(), workspace.clone(), @@ -991,23 +1030,25 @@ impl PromptEditor { thread_store.clone(), context_picker_menu_handle.clone(), SuggestContextKind::Thread, + window, cx, ) }); let context_strip_subscription = - cx.subscribe(&context_strip, Self::handle_context_strip_event); + cx.subscribe_in(&context_strip, window, Self::handle_context_strip_event); let mut this = Self { editor: prompt_editor.clone(), context_store, context_strip, context_picker_menu_handle, - model_selector: cx.new_view(|cx| { + model_selector: cx.new(|cx| { AssistantModelSelector::new( fs, model_selector_menu_handle.clone(), prompt_editor.focus_handle(cx), + window, cx, ) }), @@ -1024,11 +1065,11 @@ impl PromptEditor { _phantom: Default::default(), }; this.count_lines(cx); - this.subscribe_to_editor(cx); + this.subscribe_to_editor(window, cx); this } - fn count_lines(&mut self, cx: &mut ViewContext) { + fn count_lines(&mut self, cx: &mut Context) { let height_in_lines = cmp::max( 2, // Make the editor at least two lines tall, to account for padding and buttons. cmp::min( @@ -1052,7 +1093,7 @@ impl PromptEditor { } } - fn handle_codegen_changed(&mut self, _: Model, cx: &mut ViewContext) { + fn handle_codegen_changed(&mut self, _: Entity, cx: &mut Context) { match &self.codegen().read(cx).status { CodegenStatus::Idle => { self.editor @@ -1070,7 +1111,7 @@ impl PromptEditor { } } - pub fn codegen(&self) -> &Model { + pub fn codegen(&self) -> &Entity { match &self.mode { PromptEditorMode::Buffer { .. } => unreachable!(), PromptEditorMode::Terminal { codegen, .. } => codegen, @@ -1094,7 +1135,7 @@ fn dismissed_rate_limit_notice() -> bool { .map_or(false, |s| s.is_some()) } -fn set_rate_limit_notice_dismissed(is_dismissed: bool, cx: &mut AppContext) { +fn set_rate_limit_notice_dismissed(is_dismissed: bool, cx: &mut App) { db::write_and_log(cx, move || async move { if is_dismissed { db::kvp::KEY_VALUE_STORE diff --git a/crates/assistant2/src/message_editor.rs b/crates/assistant2/src/message_editor.rs index 667bf34ae2..70d32f3dda 100644 --- a/crates/assistant2/src/message_editor.rs +++ b/crates/assistant2/src/message_editor.rs @@ -4,8 +4,8 @@ use editor::actions::MoveUp; use editor::{Editor, EditorElement, EditorEvent, EditorStyle}; use fs::Fs; use gpui::{ - pulsating_between, Animation, AnimationExt, AppContext, DismissEvent, FocusableView, Model, - Subscription, TextStyle, View, WeakModel, WeakView, + pulsating_between, Animation, AnimationExt, App, DismissEvent, Entity, Focusable, Subscription, + TextStyle, WeakEntity, }; use language_model::{LanguageModelRegistry, LanguageModelRequestTool}; use language_model_selector::LanguageModelSelector; @@ -27,14 +27,14 @@ use crate::thread_store::ThreadStore; use crate::{Chat, ChatMode, RemoveAllContext, ToggleContextPicker, ToggleModelSelector}; pub struct MessageEditor { - thread: Model, - editor: View, - context_store: Model, - context_strip: View, + thread: Entity, + editor: Entity, + context_store: Entity, + context_strip: Entity, context_picker_menu_handle: PopoverMenuHandle, - inline_context_picker: View, + inline_context_picker: Entity, inline_context_picker_menu_handle: PopoverMenuHandle, - model_selector: View, + model_selector: Entity, model_selector_menu_handle: PopoverMenuHandle, use_tools: bool, _subscriptions: Vec, @@ -43,36 +43,38 @@ pub struct MessageEditor { impl MessageEditor { pub fn new( fs: Arc, - workspace: WeakView, - thread_store: WeakModel, - thread: Model, - cx: &mut ViewContext, + workspace: WeakEntity, + thread_store: WeakEntity, + thread: Entity, + window: &mut Window, + cx: &mut Context, ) -> Self { - let context_store = cx.new_model(|_cx| ContextStore::new(workspace.clone())); + let context_store = cx.new(|_cx| ContextStore::new(workspace.clone())); let context_picker_menu_handle = PopoverMenuHandle::default(); let inline_context_picker_menu_handle = PopoverMenuHandle::default(); let model_selector_menu_handle = PopoverMenuHandle::default(); - let editor = cx.new_view(|cx| { - let mut editor = Editor::auto_height(10, cx); + let editor = cx.new(|cx| { + let mut editor = Editor::auto_height(10, window, cx); editor.set_placeholder_text("Ask anything, @ to mention, ↑ to select", cx); editor.set_show_indent_guides(false, cx); editor }); - let inline_context_picker = cx.new_view(|cx| { + let inline_context_picker = cx.new(|cx| { ContextPicker::new( workspace.clone(), Some(thread_store.clone()), context_store.downgrade(), editor.downgrade(), ConfirmBehavior::Close, + window, cx, ) }); - let context_strip = cx.new_view(|cx| { + let context_strip = cx.new(|cx| { ContextStrip::new( context_store.clone(), workspace.clone(), @@ -80,17 +82,19 @@ impl MessageEditor { Some(thread_store.clone()), context_picker_menu_handle.clone(), SuggestContextKind::File, + window, cx, ) }); let subscriptions = vec![ - cx.subscribe(&editor, Self::handle_editor_event), - cx.subscribe( + cx.subscribe_in(&editor, window, Self::handle_editor_event), + cx.subscribe_in( &inline_context_picker, + window, Self::handle_inline_context_picker_event, ), - cx.subscribe(&context_strip, Self::handle_context_strip_event), + cx.subscribe_in(&context_strip, window, Self::handle_context_strip_event), ]; Self { @@ -101,11 +105,12 @@ impl MessageEditor { context_picker_menu_handle, inline_context_picker, inline_context_picker_menu_handle, - model_selector: cx.new_view(|cx| { + model_selector: cx.new(|cx| { AssistantModelSelector::new( fs, model_selector_menu_handle.clone(), editor.focus_handle(cx), + window, cx, ) }), @@ -115,39 +120,59 @@ impl MessageEditor { } } - fn toggle_model_selector(&mut self, _: &ToggleModelSelector, cx: &mut ViewContext) { - self.model_selector_menu_handle.toggle(cx) + fn toggle_model_selector( + &mut self, + _: &ToggleModelSelector, + window: &mut Window, + cx: &mut Context, + ) { + self.model_selector_menu_handle.toggle(window, cx) } - fn toggle_chat_mode(&mut self, _: &ChatMode, cx: &mut ViewContext) { + fn toggle_chat_mode(&mut self, _: &ChatMode, _window: &mut Window, cx: &mut Context) { self.use_tools = !self.use_tools; cx.notify(); } - fn toggle_context_picker(&mut self, _: &ToggleContextPicker, cx: &mut ViewContext) { - self.context_picker_menu_handle.toggle(cx); + fn toggle_context_picker( + &mut self, + _: &ToggleContextPicker, + window: &mut Window, + cx: &mut Context, + ) { + self.context_picker_menu_handle.toggle(window, cx); } - pub fn remove_all_context(&mut self, _: &RemoveAllContext, cx: &mut ViewContext) { + pub fn remove_all_context( + &mut self, + _: &RemoveAllContext, + _window: &mut Window, + cx: &mut Context, + ) { self.context_store.update(cx, |store, _cx| store.clear()); cx.notify(); } - fn chat(&mut self, _: &Chat, cx: &mut ViewContext) { - self.send_to_model(RequestKind::Chat, cx); + fn chat(&mut self, _: &Chat, window: &mut Window, cx: &mut Context) { + self.send_to_model(RequestKind::Chat, window, cx); } - fn is_editor_empty(&self, cx: &AppContext) -> bool { + fn is_editor_empty(&self, cx: &App) -> bool { self.editor.read(cx).text(cx).is_empty() } - fn is_model_selected(&self, cx: &AppContext) -> bool { + fn is_model_selected(&self, cx: &App) -> bool { LanguageModelRegistry::read_global(cx) .active_model() .is_some() } - fn send_to_model(&mut self, request_kind: RequestKind, cx: &mut ViewContext) { + fn send_to_model( + &mut self, + request_kind: RequestKind, + window: &mut Window, + cx: &mut Context, + ) { let provider = LanguageModelRegistry::read_global(cx).active_provider(); if provider .as_ref() @@ -164,7 +189,7 @@ impl MessageEditor { let user_message = self.editor.update(cx, |editor, cx| { let text = editor.text(cx); - editor.clear(cx); + editor.clear(window, cx); text }); @@ -203,9 +228,10 @@ impl MessageEditor { fn handle_editor_event( &mut self, - editor: View, + editor: &Entity, event: &EditorEvent, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { match event { EditorEvent::SelectionsChanged { .. } => { @@ -216,7 +242,7 @@ impl MessageEditor { let behind_cursor = Point::new(newest_cursor.row, newest_cursor.column - 1); let char_behind_cursor = snapshot.chars_at(behind_cursor).next(); if char_behind_cursor == Some('@') { - self.inline_context_picker_menu_handle.show(cx); + self.inline_context_picker_menu_handle.show(window, cx); } } }); @@ -227,52 +253,54 @@ impl MessageEditor { fn handle_inline_context_picker_event( &mut self, - _inline_context_picker: View, + _inline_context_picker: &Entity, _event: &DismissEvent, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let editor_focus_handle = self.editor.focus_handle(cx); - cx.focus(&editor_focus_handle); + window.focus(&editor_focus_handle); } fn handle_context_strip_event( &mut self, - _context_strip: View, + _context_strip: &Entity, event: &ContextStripEvent, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { match event { ContextStripEvent::PickerDismissed | ContextStripEvent::BlurredEmpty | ContextStripEvent::BlurredDown => { let editor_focus_handle = self.editor.focus_handle(cx); - cx.focus(&editor_focus_handle); + window.focus(&editor_focus_handle); } ContextStripEvent::BlurredUp => {} } } - fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext) { + fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context) { if self.context_picker_menu_handle.is_deployed() || self.inline_context_picker_menu_handle.is_deployed() { cx.propagate(); } else { - cx.focus_view(&self.context_strip); + self.context_strip.focus_handle(cx).focus(window); } } } -impl FocusableView for MessageEditor { - fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle { +impl Focusable for MessageEditor { + fn focus_handle(&self, cx: &App) -> gpui::FocusHandle { self.editor.focus_handle(cx) } } impl Render for MessageEditor { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { let font_size = TextSize::Default.rems(cx); - let line_height = font_size.to_pixels(cx.rem_size()) * 1.5; + let line_height = font_size.to_pixels(window.rem_size()) * 1.5; let focus_handle = self.editor.focus_handle(cx); let inline_context_picker = self.inline_context_picker.clone(); let bg_color = cx.theme().colors().editor_background; @@ -326,9 +354,9 @@ impl Render for MessageEditor { }) .child( PopoverMenu::new("inline-context-picker") - .menu(move |cx| { + .menu(move |window, cx| { inline_context_picker.update(cx, |this, cx| { - this.init(cx); + this.init(window, cx); }); Some(inline_context_picker.clone()) @@ -351,7 +379,7 @@ impl Render for MessageEditor { .child( Switch::new("use-tools", self.use_tools.into()) .label("Tools") - .on_click(cx.listener(|this, selection, _cx| { + .on_click(cx.listener(|this, selection, _window, _cx| { this.use_tools = match selection { ToggleState::Selected => true, ToggleState::Unselected @@ -361,7 +389,7 @@ impl Render for MessageEditor { .key_binding(KeyBinding::for_action_in( &ChatMode, &focus_handle, - cx, + window, )), ) .child(h_flex().gap_1().child(self.model_selector.clone()).child( @@ -390,14 +418,17 @@ impl Render for MessageEditor { KeyBinding::for_action_in( &editor::actions::Cancel, &focus_handle, - cx, + window, ) .map(|binding| binding.into_any_element()), ), ) - .on_click(move |_event, cx| { - focus_handle - .dispatch_action(&editor::actions::Cancel, cx); + .on_click(move |_event, window, cx| { + focus_handle.dispatch_action( + &editor::actions::Cancel, + window, + cx, + ); }) } else { ButtonLike::new("submit-message") @@ -417,23 +448,22 @@ impl Render for MessageEditor { KeyBinding::for_action_in( &Chat, &focus_handle, - cx, + window, ) .map(|binding| binding.into_any_element()), ), ) - .on_click(move |_event, cx| { - focus_handle.dispatch_action(&Chat, cx); + .on_click(move |_event, window, cx| { + focus_handle.dispatch_action(&Chat, window, cx); }) .when(is_editor_empty, |button| { - button.tooltip(|cx| { - Tooltip::text("Type a message to submit", cx) - }) + button + .tooltip(Tooltip::text("Type a message to submit")) }) .when(!is_model_selected, |button| { - button.tooltip(|cx| { - Tooltip::text("Select a model to continue", cx) - }) + button.tooltip(Tooltip::text( + "Select a model to continue", + )) }) }, )), diff --git a/crates/assistant2/src/terminal_codegen.rs b/crates/assistant2/src/terminal_codegen.rs index 97cb18e440..0bd0bfb041 100644 --- a/crates/assistant2/src/terminal_codegen.rs +++ b/crates/assistant2/src/terminal_codegen.rs @@ -1,7 +1,7 @@ use crate::inline_prompt_editor::CodegenStatus; use client::telemetry::Telemetry; use futures::{channel::mpsc, SinkExt, StreamExt}; -use gpui::{AppContext, EventEmitter, Model, ModelContext, Task}; +use gpui::{App, Context, Entity, EventEmitter, Task}; use language_model::{LanguageModelRegistry, LanguageModelRequest}; use language_models::report_assistant_event; use std::{sync::Arc, time::Instant}; @@ -11,7 +11,7 @@ use terminal::Terminal; pub struct TerminalCodegen { pub status: CodegenStatus, pub telemetry: Option>, - terminal: Model, + terminal: Entity, generation: Task<()>, pub message_id: Option, transaction: Option, @@ -20,7 +20,7 @@ pub struct TerminalCodegen { impl EventEmitter for TerminalCodegen {} impl TerminalCodegen { - pub fn new(terminal: Model, telemetry: Option>) -> Self { + pub fn new(terminal: Entity, telemetry: Option>) -> Self { Self { terminal, telemetry, @@ -31,7 +31,7 @@ impl TerminalCodegen { } } - pub fn start(&mut self, prompt: LanguageModelRequest, cx: &mut ModelContext) { + pub fn start(&mut self, prompt: LanguageModelRequest, cx: &mut Context) { let Some(model) = LanguageModelRegistry::read_global(cx).active_model() else { return; }; @@ -131,20 +131,20 @@ impl TerminalCodegen { cx.notify(); } - pub fn stop(&mut self, cx: &mut ModelContext) { + pub fn stop(&mut self, cx: &mut Context) { self.status = CodegenStatus::Done; self.generation = Task::ready(()); cx.emit(CodegenEvent::Finished); cx.notify(); } - pub fn complete(&mut self, cx: &mut ModelContext) { + pub fn complete(&mut self, cx: &mut Context) { if let Some(transaction) = self.transaction.take() { transaction.complete(cx); } } - pub fn undo(&mut self, cx: &mut ModelContext) { + pub fn undo(&mut self, cx: &mut Context) { if let Some(transaction) = self.transaction.take() { transaction.undo(cx); } @@ -160,27 +160,27 @@ pub const CLEAR_INPUT: &str = "\x15"; const CARRIAGE_RETURN: &str = "\x0d"; struct TerminalTransaction { - terminal: Model, + terminal: Entity, } impl TerminalTransaction { - pub fn start(terminal: Model) -> Self { + pub fn start(terminal: Entity) -> Self { Self { terminal } } - pub fn push(&mut self, hunk: String, cx: &mut AppContext) { + pub fn push(&mut self, hunk: String, cx: &mut App) { // Ensure that the assistant cannot accidentally execute commands that are streamed into the terminal let input = Self::sanitize_input(hunk); self.terminal .update(cx, |terminal, _| terminal.input(input)); } - pub fn undo(&self, cx: &mut AppContext) { + pub fn undo(&self, cx: &mut App) { self.terminal .update(cx, |terminal, _| terminal.input(CLEAR_INPUT.to_string())); } - pub fn complete(&self, cx: &mut AppContext) { + pub fn complete(&self, cx: &mut App) { self.terminal.update(cx, |terminal, _| { terminal.input(CARRIAGE_RETURN.to_string()) }); diff --git a/crates/assistant2/src/terminal_inline_assistant.rs b/crates/assistant2/src/terminal_inline_assistant.rs index 65be6a6e98..1c74d87f3a 100644 --- a/crates/assistant2/src/terminal_inline_assistant.rs +++ b/crates/assistant2/src/terminal_inline_assistant.rs @@ -10,10 +10,7 @@ use client::telemetry::Telemetry; use collections::{HashMap, VecDeque}; use editor::{actions::SelectAll, MultiBuffer}; use fs::Fs; -use gpui::{ - AppContext, Context, FocusableView, Global, Model, Subscription, UpdateGlobal, View, WeakModel, - WeakView, -}; +use gpui::{App, Entity, Focusable, Global, Subscription, UpdateGlobal, WeakEntity}; use language::Buffer; use language_model::{ LanguageModelRegistry, LanguageModelRequest, LanguageModelRequestMessage, Role, @@ -31,7 +28,7 @@ pub fn init( fs: Arc, prompt_builder: Arc, telemetry: Arc, - cx: &mut AppContext, + cx: &mut App, ) { cx.set_global(TerminalInlineAssistant::new(fs, prompt_builder, telemetry)); } @@ -68,20 +65,20 @@ impl TerminalInlineAssistant { pub fn assist( &mut self, - terminal_view: &View, - workspace: WeakView, - thread_store: Option>, - cx: &mut WindowContext, + terminal_view: &Entity, + workspace: WeakEntity, + thread_store: Option>, + window: &mut Window, + cx: &mut App, ) { let terminal = terminal_view.read(cx).terminal().clone(); let assist_id = self.next_assist_id.post_inc(); - let prompt_buffer = cx.new_model(|cx| { - MultiBuffer::singleton(cx.new_model(|cx| Buffer::local(String::new(), cx)), cx) - }); - let context_store = cx.new_model(|_cx| ContextStore::new(workspace.clone())); - let codegen = cx.new_model(|_| TerminalCodegen::new(terminal, self.telemetry.clone())); + let prompt_buffer = + cx.new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(String::new(), cx)), cx)); + let context_store = cx.new(|_cx| ContextStore::new(workspace.clone())); + let codegen = cx.new(|_| TerminalCodegen::new(terminal, self.telemetry.clone())); - let prompt_editor = cx.new_view(|cx| { + let prompt_editor = cx.new(|cx| { PromptEditor::new_terminal( assist_id, self.prompt_history.clone(), @@ -91,6 +88,7 @@ impl TerminalInlineAssistant { context_store.clone(), workspace.clone(), thread_store.clone(), + window, cx, ) }); @@ -100,7 +98,7 @@ impl TerminalInlineAssistant { render: Box::new(move |_| prompt_editor_render.clone().into_any_element()), }; terminal_view.update(cx, |terminal_view, cx| { - terminal_view.set_block_below_cursor(block, cx); + terminal_view.set_block_below_cursor(block, window, cx); }); let terminal_assistant = TerminalInlineAssist::new( @@ -109,21 +107,27 @@ impl TerminalInlineAssistant { prompt_editor, workspace.clone(), context_store, + window, cx, ); self.assists.insert(assist_id, terminal_assistant); - self.focus_assist(assist_id, cx); + self.focus_assist(assist_id, window, cx); } - fn focus_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut WindowContext) { + fn focus_assist( + &mut self, + assist_id: TerminalInlineAssistId, + window: &mut Window, + cx: &mut App, + ) { let assist = &self.assists[&assist_id]; if let Some(prompt_editor) = assist.prompt_editor.as_ref() { prompt_editor.update(cx, |this, cx| { this.editor.update(cx, |editor, cx| { - editor.focus(cx); - editor.select_all(&SelectAll, cx); + window.focus(&editor.focus_handle(cx)); + editor.select_all(&SelectAll, window, cx); }); }); } @@ -131,9 +135,10 @@ impl TerminalInlineAssistant { fn handle_prompt_editor_event( &mut self, - prompt_editor: View>, + prompt_editor: Entity>, event: &PromptEditorEvent, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { let assist_id = prompt_editor.read(cx).id(); match event { @@ -144,21 +149,21 @@ impl TerminalInlineAssistant { self.stop_assist(assist_id, cx); } PromptEditorEvent::ConfirmRequested { execute } => { - self.finish_assist(assist_id, false, *execute, cx); + self.finish_assist(assist_id, false, *execute, window, cx); } PromptEditorEvent::CancelRequested => { - self.finish_assist(assist_id, true, false, cx); + self.finish_assist(assist_id, true, false, window, cx); } PromptEditorEvent::DismissRequested => { - self.dismiss_assist(assist_id, cx); + self.dismiss_assist(assist_id, window, cx); } PromptEditorEvent::Resized { height_in_lines } => { - self.insert_prompt_editor_into_terminal(assist_id, *height_in_lines, cx); + self.insert_prompt_editor_into_terminal(assist_id, *height_in_lines, window, cx); } } } - fn start_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut WindowContext) { + fn start_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut App) { let assist = if let Some(assist) = self.assists.get_mut(&assist_id) { assist } else { @@ -196,7 +201,7 @@ impl TerminalInlineAssistant { codegen.update(cx, |codegen, cx| codegen.start(request, cx)); } - fn stop_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut WindowContext) { + fn stop_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut App) { let assist = if let Some(assist) = self.assists.get_mut(&assist_id) { assist } else { @@ -209,7 +214,7 @@ impl TerminalInlineAssistant { fn request_for_inline_assist( &self, assist_id: TerminalInlineAssistId, - cx: &mut WindowContext, + cx: &mut App, ) -> Result { let assist = self.assists.get(&assist_id).context("invalid assist")?; @@ -265,16 +270,17 @@ impl TerminalInlineAssistant { assist_id: TerminalInlineAssistId, undo: bool, execute: bool, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { - self.dismiss_assist(assist_id, cx); + self.dismiss_assist(assist_id, window, cx); if let Some(assist) = self.assists.remove(&assist_id) { assist .terminal .update(cx, |this, cx| { this.clear_block_below_cursor(cx); - this.focus_handle(cx).focus(cx); + this.focus_handle(cx).focus(window); }) .log_err(); @@ -317,7 +323,8 @@ impl TerminalInlineAssistant { fn dismiss_assist( &mut self, assist_id: TerminalInlineAssistId, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> bool { let Some(assist) = self.assists.get_mut(&assist_id) else { return false; @@ -330,7 +337,7 @@ impl TerminalInlineAssistant { .terminal .update(cx, |this, cx| { this.clear_block_below_cursor(cx); - this.focus_handle(cx).focus(cx); + this.focus_handle(cx).focus(window); }) .is_ok() } @@ -339,7 +346,8 @@ impl TerminalInlineAssistant { &mut self, assist_id: TerminalInlineAssistId, height: u8, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) { if let Some(assist) = self.assists.get_mut(&assist_id) { if let Some(prompt_editor) = assist.prompt_editor.as_ref().cloned() { @@ -351,7 +359,7 @@ impl TerminalInlineAssistant { height, render: Box::new(move |_| prompt_editor.clone().into_any_element()), }; - terminal.set_block_below_cursor(block, cx); + terminal.set_block_below_cursor(block, window, cx); }) .log_err(); } @@ -360,22 +368,23 @@ impl TerminalInlineAssistant { } struct TerminalInlineAssist { - terminal: WeakView, - prompt_editor: Option>>, - codegen: Model, - workspace: WeakView, - context_store: Model, + terminal: WeakEntity, + prompt_editor: Option>>, + codegen: Entity, + workspace: WeakEntity, + context_store: Entity, _subscriptions: Vec, } impl TerminalInlineAssist { pub fn new( assist_id: TerminalInlineAssistId, - terminal: &View, - prompt_editor: View>, - workspace: WeakView, - context_store: Model, - cx: &mut WindowContext, + terminal: &Entity, + prompt_editor: Entity>, + workspace: WeakEntity, + context_store: Entity, + window: &mut Window, + cx: &mut App, ) -> Self { let codegen = prompt_editor.read(cx).codegen().clone(); Self { @@ -385,12 +394,12 @@ impl TerminalInlineAssist { workspace: workspace.clone(), context_store, _subscriptions: vec![ - cx.subscribe(&prompt_editor, |prompt_editor, event, cx| { + window.subscribe(&prompt_editor, cx, |prompt_editor, event, window, cx| { TerminalInlineAssistant::update_global(cx, |this, cx| { - this.handle_prompt_editor_event(prompt_editor, event, cx) + this.handle_prompt_editor_event(prompt_editor, event, window, cx) }) }), - cx.subscribe(&codegen, move |codegen, event, cx| { + window.subscribe(&codegen, cx, move |codegen, event, window, cx| { TerminalInlineAssistant::update_global(cx, |this, cx| match event { CodegenEvent::Finished => { let assist = if let Some(assist) = this.assists.get(&assist_id) { @@ -419,7 +428,7 @@ impl TerminalInlineAssist { } if assist.prompt_editor.is_none() { - this.finish_assist(assist_id, false, false, cx); + this.finish_assist(assist_id, false, false, window, cx); } } }) diff --git a/crates/assistant2/src/thread.rs b/crates/assistant2/src/thread.rs index 57cc0c3b87..9ccb066480 100644 --- a/crates/assistant2/src/thread.rs +++ b/crates/assistant2/src/thread.rs @@ -6,7 +6,7 @@ use chrono::{DateTime, Utc}; use collections::{BTreeMap, HashMap, HashSet}; use futures::future::Shared; use futures::{FutureExt as _, StreamExt as _}; -use gpui::{AppContext, EventEmitter, ModelContext, SharedString, Task}; +use gpui::{App, Context, EventEmitter, SharedString, Task}; use language_model::{ LanguageModel, LanguageModelCompletionEvent, LanguageModelRegistry, LanguageModelRequest, LanguageModelRequestMessage, LanguageModelToolResult, LanguageModelToolUse, @@ -76,7 +76,7 @@ pub struct Thread { } impl Thread { - pub fn new(tools: Arc, _cx: &mut ModelContext) -> Self { + pub fn new(tools: Arc, _cx: &mut Context) -> Self { Self { id: ThreadId::new(), updated_at: Utc::now(), @@ -99,7 +99,7 @@ impl Thread { id: ThreadId, saved: SavedThread, tools: Arc, - _cx: &mut ModelContext, + _cx: &mut Context, ) -> Self { let next_message_id = MessageId(saved.messages.len()); @@ -154,7 +154,7 @@ impl Thread { self.summary.clone().unwrap_or(DEFAULT) } - pub fn set_summary(&mut self, summary: impl Into, cx: &mut ModelContext) { + pub fn set_summary(&mut self, summary: impl Into, cx: &mut Context) { self.summary = Some(summary.into()); cx.emit(ThreadEvent::SummaryChanged); } @@ -194,7 +194,7 @@ impl Thread { &mut self, text: impl Into, context: Vec, - cx: &mut ModelContext, + cx: &mut Context, ) { let message_id = self.insert_message(Role::User, text, cx); let context_ids = context.iter().map(|context| context.id).collect::>(); @@ -207,7 +207,7 @@ impl Thread { &mut self, role: Role, text: impl Into, - cx: &mut ModelContext, + cx: &mut Context, ) -> MessageId { let id = self.next_message_id.post_inc(); self.messages.push(Message { @@ -244,7 +244,7 @@ impl Thread { pub fn to_completion_request( &self, _request_kind: RequestKind, - _cx: &AppContext, + _cx: &App, ) -> LanguageModelRequest { let mut request = LanguageModelRequest { messages: vec![], @@ -314,7 +314,7 @@ impl Thread { &mut self, request: LanguageModelRequest, model: Arc, - cx: &mut ModelContext, + cx: &mut Context, ) { let pending_completion_id = post_inc(&mut self.completion_count); @@ -439,7 +439,7 @@ impl Thread { }); } - pub fn summarize(&mut self, cx: &mut ModelContext) { + pub fn summarize(&mut self, cx: &mut Context) { let Some(provider) = LanguageModelRegistry::read_global(cx).active_provider() else { return; }; @@ -497,7 +497,7 @@ impl Thread { assistant_message_id: MessageId, tool_use_id: LanguageModelToolUseId, output: Task>, - cx: &mut ModelContext, + cx: &mut Context, ) { let insert_output_task = cx.spawn(|thread, mut cx| { let tool_use_id = tool_use_id.clone(); diff --git a/crates/assistant2/src/thread_history.rs b/crates/assistant2/src/thread_history.rs index eeb1bae84c..9e77f3d94b 100644 --- a/crates/assistant2/src/thread_history.rs +++ b/crates/assistant2/src/thread_history.rs @@ -1,6 +1,6 @@ use gpui::{ - uniform_list, AppContext, FocusHandle, FocusableView, Model, ScrollStrategy, - UniformListScrollHandle, WeakView, + uniform_list, App, Entity, FocusHandle, Focusable, ScrollStrategy, UniformListScrollHandle, + WeakEntity, }; use time::{OffsetDateTime, UtcOffset}; use ui::{prelude::*, IconButtonShape, ListItem, ListItemSpacing, Tooltip}; @@ -10,17 +10,18 @@ use crate::{AssistantPanel, RemoveSelectedThread}; pub struct ThreadHistory { focus_handle: FocusHandle, - assistant_panel: WeakView, - thread_store: Model, + assistant_panel: WeakEntity, + thread_store: Entity, scroll_handle: UniformListScrollHandle, selected_index: usize, } impl ThreadHistory { pub(crate) fn new( - assistant_panel: WeakView, - thread_store: Model, - cx: &mut ViewContext, + assistant_panel: WeakEntity, + thread_store: Entity, + + cx: &mut Context, ) -> Self { Self { focus_handle: cx.focus_handle(), @@ -31,62 +32,77 @@ impl ThreadHistory { } } - pub fn select_prev(&mut self, _: &menu::SelectPrev, cx: &mut ViewContext) { + pub fn select_prev( + &mut self, + _: &menu::SelectPrev, + window: &mut Window, + cx: &mut Context, + ) { let count = self.thread_store.read(cx).thread_count(); if count > 0 { if self.selected_index == 0 { - self.set_selected_index(count - 1, cx); + self.set_selected_index(count - 1, window, cx); } else { - self.set_selected_index(self.selected_index - 1, cx); + self.set_selected_index(self.selected_index - 1, window, cx); } } } - pub fn select_next(&mut self, _: &menu::SelectNext, cx: &mut ViewContext) { + pub fn select_next( + &mut self, + _: &menu::SelectNext, + window: &mut Window, + cx: &mut Context, + ) { let count = self.thread_store.read(cx).thread_count(); if count > 0 { if self.selected_index == count - 1 { - self.set_selected_index(0, cx); + self.set_selected_index(0, window, cx); } else { - self.set_selected_index(self.selected_index + 1, cx); + self.set_selected_index(self.selected_index + 1, window, cx); } } } - fn select_first(&mut self, _: &menu::SelectFirst, cx: &mut ViewContext) { + fn select_first(&mut self, _: &menu::SelectFirst, window: &mut Window, cx: &mut Context) { let count = self.thread_store.read(cx).thread_count(); if count > 0 { - self.set_selected_index(0, cx); + self.set_selected_index(0, window, cx); } } - fn select_last(&mut self, _: &menu::SelectLast, cx: &mut ViewContext) { + fn select_last(&mut self, _: &menu::SelectLast, window: &mut Window, cx: &mut Context) { let count = self.thread_store.read(cx).thread_count(); if count > 0 { - self.set_selected_index(count - 1, cx); + self.set_selected_index(count - 1, window, cx); } } - fn set_selected_index(&mut self, index: usize, cx: &mut ViewContext) { + fn set_selected_index(&mut self, index: usize, _window: &mut Window, cx: &mut Context) { self.selected_index = index; self.scroll_handle .scroll_to_item(index, ScrollStrategy::Top); cx.notify(); } - fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext) { + fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context) { let threads = self.thread_store.update(cx, |this, _cx| this.threads()); if let Some(thread) = threads.get(self.selected_index) { self.assistant_panel - .update(cx, move |this, cx| this.open_thread(&thread.id, cx)) + .update(cx, move |this, cx| this.open_thread(&thread.id, window, cx)) .ok(); cx.notify(); } } - fn remove_selected_thread(&mut self, _: &RemoveSelectedThread, cx: &mut ViewContext) { + fn remove_selected_thread( + &mut self, + _: &RemoveSelectedThread, + _window: &mut Window, + cx: &mut Context, + ) { let threads = self.thread_store.update(cx, |this, _cx| this.threads()); if let Some(thread) = threads.get(self.selected_index) { @@ -101,14 +117,14 @@ impl ThreadHistory { } } -impl FocusableView for ThreadHistory { - fn focus_handle(&self, _cx: &AppContext) -> FocusHandle { +impl Focusable for ThreadHistory { + fn focus_handle(&self, _cx: &App) -> FocusHandle { self.focus_handle.clone() } } impl Render for ThreadHistory { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { let threads = self.thread_store.update(cx, |this, _cx| this.threads()); let selected_index = self.selected_index; @@ -138,10 +154,10 @@ impl Render for ThreadHistory { } else { history.child( uniform_list( - cx.view().clone(), + cx.model().clone(), "thread-history", threads.len(), - move |history, range, _cx| { + move |history, range, _window, _cx| { threads[range] .iter() .enumerate() @@ -166,14 +182,14 @@ impl Render for ThreadHistory { #[derive(IntoElement)] pub struct PastThread { thread: SavedThreadMetadata, - assistant_panel: WeakView, + assistant_panel: WeakEntity, selected: bool, } impl PastThread { pub fn new( thread: SavedThreadMetadata, - assistant_panel: WeakView, + assistant_panel: WeakEntity, selected: bool, ) -> Self { Self { @@ -185,7 +201,7 @@ impl PastThread { } impl RenderOnce for PastThread { - fn render(self, cx: &mut WindowContext) -> impl IntoElement { + fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { let summary = self.thread.summary; let thread_timestamp = time_format::format_localized_timestamp( @@ -219,11 +235,11 @@ impl RenderOnce for PastThread { IconButton::new("delete", IconName::TrashAlt) .shape(IconButtonShape::Square) .icon_size(IconSize::Small) - .tooltip(|cx| Tooltip::text("Delete Thread", cx)) + .tooltip(Tooltip::text("Delete Thread")) .on_click({ let assistant_panel = self.assistant_panel.clone(); let id = self.thread.id.clone(); - move |_event, cx| { + move |_event, _window, cx| { assistant_panel .update(cx, |this, cx| { this.delete_thread(&id, cx); @@ -236,10 +252,10 @@ impl RenderOnce for PastThread { .on_click({ let assistant_panel = self.assistant_panel.clone(); let id = self.thread.id.clone(); - move |_event, cx| { + move |_event, window, cx| { assistant_panel .update(cx, |this, cx| { - this.open_thread(&id, cx).detach_and_log_err(cx); + this.open_thread(&id, window, cx).detach_and_log_err(cx); }) .ok(); } diff --git a/crates/assistant2/src/thread_store.rs b/crates/assistant2/src/thread_store.rs index ee377649a1..1d055d788c 100644 --- a/crates/assistant2/src/thread_store.rs +++ b/crates/assistant2/src/thread_store.rs @@ -9,7 +9,7 @@ use context_server::manager::ContextServerManager; use context_server::{ContextServerFactoryRegistry, ContextServerTool}; use futures::future::{self, BoxFuture, Shared}; use futures::FutureExt as _; -use gpui::{prelude::*, AppContext, BackgroundExecutor, Model, ModelContext, SharedString, Task}; +use gpui::{prelude::*, App, BackgroundExecutor, Context, Entity, SharedString, Task}; use heed::types::SerdeBincode; use heed::Database; use language_model::Role; @@ -21,9 +21,9 @@ use crate::thread::{MessageId, Thread, ThreadId}; pub struct ThreadStore { #[allow(unused)] - project: Model, + project: Entity, tools: Arc, - context_server_manager: Model, + context_server_manager: Entity, context_server_tool_ids: HashMap, Vec>, threads: Vec, database_future: Shared, Arc>>>, @@ -31,15 +31,15 @@ pub struct ThreadStore { impl ThreadStore { pub fn new( - project: Model, + project: Entity, tools: Arc, - cx: &mut AppContext, - ) -> Task>> { + cx: &mut App, + ) -> Task>> { cx.spawn(|mut cx| async move { - let this = cx.new_model(|cx: &mut ModelContext| { + let this = cx.new(|cx: &mut Context| { let context_server_factory_registry = ContextServerFactoryRegistry::default_global(cx); - let context_server_manager = cx.new_model(|cx| { + let context_server_manager = cx.new(|cx| { ContextServerManager::new(context_server_factory_registry, project.clone(), cx) }); @@ -88,15 +88,15 @@ impl ThreadStore { self.threads().into_iter().take(limit).collect() } - pub fn create_thread(&mut self, cx: &mut ModelContext) -> Model { - cx.new_model(|cx| Thread::new(self.tools.clone(), cx)) + pub fn create_thread(&mut self, cx: &mut Context) -> Entity { + cx.new(|cx| Thread::new(self.tools.clone(), cx)) } pub fn open_thread( &self, id: &ThreadId, - cx: &mut ModelContext, - ) -> Task>> { + cx: &mut Context, + ) -> Task>> { let id = id.clone(); let database_future = self.database_future.clone(); cx.spawn(|this, mut cx| async move { @@ -107,16 +107,12 @@ impl ThreadStore { .ok_or_else(|| anyhow!("no thread found with ID: {id:?}"))?; this.update(&mut cx, |this, cx| { - cx.new_model(|cx| Thread::from_saved(id.clone(), thread, this.tools.clone(), cx)) + cx.new(|cx| Thread::from_saved(id.clone(), thread, this.tools.clone(), cx)) }) }) } - pub fn save_thread( - &self, - thread: &Model, - cx: &mut ModelContext, - ) -> Task> { + pub fn save_thread(&self, thread: &Entity, cx: &mut Context) -> Task> { let (metadata, thread) = thread.update(cx, |thread, _cx| { let id = thread.id().clone(); let thread = SavedThread { @@ -144,11 +140,7 @@ impl ThreadStore { }) } - pub fn delete_thread( - &mut self, - id: &ThreadId, - cx: &mut ModelContext, - ) -> Task> { + pub fn delete_thread(&mut self, id: &ThreadId, cx: &mut Context) -> Task> { let id = id.clone(); let database_future = self.database_future.clone(); cx.spawn(|this, mut cx| async move { @@ -161,7 +153,7 @@ impl ThreadStore { }) } - fn reload(&self, cx: &mut ModelContext) -> Task> { + fn reload(&self, cx: &mut Context) -> Task> { let database_future = self.database_future.clone(); cx.spawn(|this, mut cx| async move { let threads = database_future @@ -177,7 +169,7 @@ impl ThreadStore { }) } - fn register_context_server_handlers(&self, cx: &mut ModelContext) { + fn register_context_server_handlers(&self, cx: &mut Context) { cx.subscribe( &self.context_server_manager.clone(), Self::handle_context_server_event, @@ -187,9 +179,9 @@ impl ThreadStore { fn handle_context_server_event( &mut self, - context_server_manager: Model, + context_server_manager: Entity, event: &context_server::manager::Event, - cx: &mut ModelContext, + cx: &mut Context, ) { let tool_working_set = self.tools.clone(); match event { diff --git a/crates/assistant2/src/ui/context_pill.rs b/crates/assistant2/src/ui/context_pill.rs index 58ec54a2d4..48886388bf 100644 --- a/crates/assistant2/src/ui/context_pill.rs +++ b/crates/assistant2/src/ui/context_pill.rs @@ -11,15 +11,15 @@ pub enum ContextPill { context: ContextSnapshot, dupe_name: bool, focused: bool, - on_click: Option>, - on_remove: Option>, + on_click: Option>, + on_remove: Option>, }, Suggested { name: SharedString, icon_path: Option, kind: ContextKind, focused: bool, - on_click: Option>, + on_click: Option>, }, } @@ -28,7 +28,7 @@ impl ContextPill { context: ContextSnapshot, dupe_name: bool, focused: bool, - on_remove: Option>, + on_remove: Option>, ) -> Self { Self::Added { context, @@ -54,7 +54,7 @@ impl ContextPill { } } - pub fn on_click(mut self, listener: Rc) -> Self { + pub fn on_click(mut self, listener: Rc) -> Self { match &mut self { ContextPill::Added { on_click, .. } => { *on_click = Some(listener); @@ -95,7 +95,7 @@ impl ContextPill { } impl RenderOnce for ContextPill { - fn render(self, cx: &mut WindowContext) -> impl IntoElement { + fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { let color = cx.theme().colors(); let base_pill = h_flex() @@ -139,7 +139,7 @@ impl RenderOnce for ContextPill { } }) .when_some(context.tooltip.clone(), |element, tooltip| { - element.tooltip(move |cx| Tooltip::text(tooltip.clone(), cx)) + element.tooltip(Tooltip::text(tooltip.clone())) }), ) .when_some(on_remove.as_ref(), |element, on_remove| { @@ -147,16 +147,16 @@ impl RenderOnce for ContextPill { IconButton::new(("remove", context.id.0), IconName::Close) .shape(IconButtonShape::Square) .icon_size(IconSize::XSmall) - .tooltip(|cx| Tooltip::text("Remove Context", cx)) + .tooltip(Tooltip::text("Remove Context")) .on_click({ let on_remove = on_remove.clone(); - move |event, cx| on_remove(event, cx) + move |event, window, cx| on_remove(event, window, cx) }), ) }) .when_some(on_click.as_ref(), |element, on_click| { let on_click = on_click.clone(); - element.on_click(move |event, cx| on_click(event, cx)) + element.on_click(move |event, window, cx| on_click(event, window, cx)) }), ContextPill::Suggested { name, @@ -195,10 +195,12 @@ impl RenderOnce for ContextPill { .size(IconSize::XSmall) .into_any_element(), ) - .tooltip(|cx| Tooltip::with_meta("Suggested Context", None, "Click to add it", cx)) + .tooltip(|window, cx| { + Tooltip::with_meta("Suggested Context", None, "Click to add it", window, cx) + }) .when_some(on_click.as_ref(), |element, on_click| { let on_click = on_click.clone(); - element.on_click(move |event, cx| on_click(event, cx)) + element.on_click(move |event, window, cx| on_click(event, window, cx)) }), } } diff --git a/crates/assistant_context_editor/src/assistant_context_editor.rs b/crates/assistant_context_editor/src/assistant_context_editor.rs index 5612a02a45..b399059beb 100644 --- a/crates/assistant_context_editor/src/assistant_context_editor.rs +++ b/crates/assistant_context_editor/src/assistant_context_editor.rs @@ -9,7 +9,7 @@ mod slash_command_picker; use std::sync::Arc; use client::Client; -use gpui::AppContext; +use gpui::App; pub use crate::context::*; pub use crate::context_editor::*; @@ -18,6 +18,6 @@ pub use crate::context_store::*; pub use crate::patch::*; pub use crate::slash_command::*; -pub fn init(client: Arc, _cx: &mut AppContext) { +pub fn init(client: Arc, _cx: &mut App) { context_store::init(&client.into()); } diff --git a/crates/assistant_context_editor/src/context.rs b/crates/assistant_context_editor/src/context.rs index edd17a5287..ba3f3527c2 100644 --- a/crates/assistant_context_editor/src/context.rs +++ b/crates/assistant_context_editor/src/context.rs @@ -16,8 +16,8 @@ use feature_flags::{FeatureFlagAppExt, ToolUseFeatureFlag}; use fs::{Fs, RemoveOptions}; use futures::{future::Shared, FutureExt, StreamExt}; use gpui::{ - AppContext, Context as _, EventEmitter, Model, ModelContext, RenderImage, SharedString, - Subscription, Task, + App, AppContext as _, Context, Entity, EventEmitter, RenderImage, SharedString, Subscription, + Task, }; use language::{AnchorRangeExt, Bias, Buffer, LanguageRegistry, OffsetRangeExt, Point, ToOffset}; use language_model::{ @@ -588,13 +588,13 @@ pub enum XmlTagKind { Operation, } -pub struct Context { +pub struct AssistantContext { id: ContextId, timestamp: clock::Lamport, version: clock::Global, pending_ops: Vec, operations: Vec, - buffer: Model, + buffer: Entity, parsed_slash_commands: Vec, invoked_slash_commands: HashMap, edits_since_last_parse: language::Subscription, @@ -619,7 +619,7 @@ pub struct Context { language_registry: Arc, patches: Vec, xml_tags: Vec, - project: Option>, + project: Option>, prompt_builder: Arc, } @@ -645,17 +645,17 @@ impl ContextAnnotation for XmlTag { } } -impl EventEmitter for Context {} +impl EventEmitter for AssistantContext {} -impl Context { +impl AssistantContext { pub fn local( language_registry: Arc, - project: Option>, + project: Option>, telemetry: Option>, prompt_builder: Arc, slash_commands: Arc, tools: Arc, - cx: &mut ModelContext, + cx: &mut Context, ) -> Self { Self::new( ContextId::new(), @@ -680,11 +680,11 @@ impl Context { prompt_builder: Arc, slash_commands: Arc, tools: Arc, - project: Option>, + project: Option>, telemetry: Option>, - cx: &mut ModelContext, + cx: &mut Context, ) -> Self { - let buffer = cx.new_model(|_cx| { + let buffer = cx.new(|_cx| { let buffer = Buffer::remote( language::BufferId::new(1).unwrap(), replica_id, @@ -755,7 +755,7 @@ impl Context { this } - pub(crate) fn serialize(&self, cx: &AppContext) -> SavedContext { + pub(crate) fn serialize(&self, cx: &App) -> SavedContext { let buffer = self.buffer.read(cx); SavedContext { id: Some(self.id.clone()), @@ -803,9 +803,9 @@ impl Context { prompt_builder: Arc, slash_commands: Arc, tools: Arc, - project: Option>, + project: Option>, telemetry: Option>, - cx: &mut ModelContext, + cx: &mut Context, ) -> Self { let id = saved_context.id.clone().unwrap_or_else(ContextId::new); let mut this = Self::new( @@ -837,7 +837,7 @@ impl Context { self.timestamp.replica_id } - pub fn version(&self, cx: &AppContext) -> ContextVersion { + pub fn version(&self, cx: &App) -> ContextVersion { ContextVersion { context: self.version.clone(), buffer: self.buffer.read(cx).version(), @@ -852,11 +852,7 @@ impl Context { &self.tools } - pub fn set_capability( - &mut self, - capability: language::Capability, - cx: &mut ModelContext, - ) { + pub fn set_capability(&mut self, capability: language::Capability, cx: &mut Context) { self.buffer .update(cx, |buffer, cx| buffer.set_capability(capability, cx)); } @@ -870,7 +866,7 @@ impl Context { pub fn serialize_ops( &self, since: &ContextVersion, - cx: &AppContext, + cx: &App, ) -> Task> { let buffer_ops = self .buffer @@ -905,7 +901,7 @@ impl Context { pub fn apply_ops( &mut self, ops: impl IntoIterator, - cx: &mut ModelContext, + cx: &mut Context, ) { let mut buffer_ops = Vec::new(); for op in ops { @@ -919,7 +915,7 @@ impl Context { self.flush_ops(cx); } - fn flush_ops(&mut self, cx: &mut ModelContext) { + fn flush_ops(&mut self, cx: &mut Context) { let mut changed_messages = HashSet::default(); let mut summary_changed = false; @@ -1038,7 +1034,7 @@ impl Context { } } - fn can_apply_op(&self, op: &ContextOperation, cx: &AppContext) -> bool { + fn can_apply_op(&self, op: &ContextOperation, cx: &App) -> bool { if !self.version.observed_all(op.version()) { return false; } @@ -1069,7 +1065,7 @@ impl Context { fn has_received_operations_for_anchor_range( &self, range: Range, - cx: &AppContext, + cx: &App, ) -> bool { let version = &self.buffer.read(cx).version; let observed_start = range.start == language::Anchor::MIN @@ -1081,12 +1077,12 @@ impl Context { observed_start && observed_end } - fn push_op(&mut self, op: ContextOperation, cx: &mut ModelContext) { + fn push_op(&mut self, op: ContextOperation, cx: &mut Context) { self.operations.push(op.clone()); cx.emit(ContextEvent::Operation(op)); } - pub fn buffer(&self) -> &Model { + pub fn buffer(&self) -> &Entity { &self.buffer } @@ -1094,7 +1090,7 @@ impl Context { self.language_registry.clone() } - pub fn project(&self) -> Option> { + pub fn project(&self) -> Option> { self.project.clone() } @@ -1110,7 +1106,7 @@ impl Context { self.summary.as_ref() } - pub fn patch_containing(&self, position: Point, cx: &AppContext) -> Option<&AssistantPatch> { + pub fn patch_containing(&self, position: Point, cx: &App) -> Option<&AssistantPatch> { let buffer = self.buffer.read(cx); let index = self.patches.binary_search_by(|patch| { let patch_range = patch.range.to_point(&buffer); @@ -1136,7 +1132,7 @@ impl Context { pub fn patch_for_range( &self, range: &Range, - cx: &AppContext, + cx: &App, ) -> Option<&AssistantPatch> { let buffer = self.buffer.read(cx); let index = self.patch_index_for_range(range, buffer).ok()?; @@ -1167,7 +1163,7 @@ impl Context { &self.slash_command_output_sections } - pub fn contains_files(&self, cx: &AppContext) -> bool { + pub fn contains_files(&self, cx: &App) -> bool { let buffer = self.buffer.read(cx); self.slash_command_output_sections.iter().any(|section| { section.is_valid(buffer) @@ -1189,7 +1185,7 @@ impl Context { self.pending_tool_uses_by_id.get(id) } - fn set_language(&mut self, cx: &mut ModelContext) { + fn set_language(&mut self, cx: &mut Context) { let markdown = self.language_registry.language_for_name("Markdown"); cx.spawn(|this, mut cx| async move { let markdown = markdown.await?; @@ -1203,9 +1199,9 @@ impl Context { fn handle_buffer_event( &mut self, - _: Model, + _: Entity, event: &language::BufferEvent, - cx: &mut ModelContext, + cx: &mut Context, ) { match event { language::BufferEvent::Operation { @@ -1227,7 +1223,7 @@ impl Context { self.token_count } - pub(crate) fn count_remaining_tokens(&mut self, cx: &mut ModelContext) { + pub(crate) fn count_remaining_tokens(&mut self, cx: &mut Context) { // Assume it will be a Chat request, even though that takes fewer tokens (and risks going over the limit), // because otherwise you see in the UI that your empty message has a bunch of tokens already used. let request = self.to_completion_request(RequestType::Chat, cx); @@ -1255,7 +1251,7 @@ impl Context { &mut self, cache_configuration: &Option, speculative: bool, - cx: &mut ModelContext, + cx: &mut Context, ) -> bool { let cache_configuration = cache_configuration @@ -1357,7 +1353,7 @@ impl Context { new_anchor_needs_caching } - fn start_cache_warming(&mut self, model: &Arc, cx: &mut ModelContext) { + fn start_cache_warming(&mut self, model: &Arc, cx: &mut Context) { let cache_configuration = model.cache_configuration(); if !self.mark_cache_anchors(&cache_configuration, true, cx) { @@ -1407,7 +1403,7 @@ impl Context { }); } - pub fn update_cache_status_for_completion(&mut self, cx: &mut ModelContext) { + pub fn update_cache_status_for_completion(&mut self, cx: &mut Context) { let cached_message_ids: Vec = self .messages_metadata .iter() @@ -1432,7 +1428,7 @@ impl Context { cx.notify(); } - pub fn reparse(&mut self, cx: &mut ModelContext) { + pub fn reparse(&mut self, cx: &mut Context) { let buffer = self.buffer.read(cx).text_snapshot(); let mut row_ranges = self .edits_since_last_parse @@ -1505,7 +1501,7 @@ impl Context { buffer: &BufferSnapshot, updated: &mut Vec, removed: &mut Vec>, - cx: &AppContext, + cx: &App, ) { let old_range = self.pending_command_indices_for_range(range.clone(), cx); @@ -1559,7 +1555,7 @@ impl Context { fn invalidate_pending_slash_commands( &mut self, buffer: &BufferSnapshot, - cx: &mut ModelContext, + cx: &mut Context, ) { let mut invalidated_command_ids = Vec::new(); for (&command_id, command) in self.invoked_slash_commands.iter_mut() { @@ -1593,7 +1589,7 @@ impl Context { buffer: &BufferSnapshot, updated: &mut Vec>, removed: &mut Vec>, - cx: &mut ModelContext, + cx: &mut Context, ) { // Rebuild the XML tags in the edited range. let intersecting_tags_range = @@ -1636,7 +1632,7 @@ impl Context { &self, buffer: &BufferSnapshot, range: Range, - cx: &AppContext, + cx: &App, ) -> Vec { let mut messages = self.messages(cx).peekable(); @@ -1693,7 +1689,7 @@ impl Context { tags_start_ix: usize, buffer_end: text::Anchor, buffer: &BufferSnapshot, - cx: &AppContext, + cx: &App, ) -> Vec { let mut new_patches = Vec::new(); let mut pending_patch = None; @@ -1851,7 +1847,7 @@ impl Context { pub fn pending_command_for_position( &mut self, position: language::Anchor, - cx: &mut ModelContext, + cx: &mut Context, ) -> Option<&mut ParsedSlashCommand> { let buffer = self.buffer.read(cx); match self @@ -1875,7 +1871,7 @@ impl Context { pub fn pending_commands_for_range( &self, range: Range, - cx: &AppContext, + cx: &App, ) -> &[ParsedSlashCommand] { let range = self.pending_command_indices_for_range(range, cx); &self.parsed_slash_commands[range] @@ -1884,7 +1880,7 @@ impl Context { fn pending_command_indices_for_range( &self, range: Range, - cx: &AppContext, + cx: &App, ) -> Range { self.indices_intersecting_buffer_range(&self.parsed_slash_commands, range, cx) } @@ -1893,7 +1889,7 @@ impl Context { &self, all_annotations: &[T], range: Range, - cx: &AppContext, + cx: &App, ) -> Range { let buffer = self.buffer.read(cx); let start_ix = match all_annotations @@ -1916,7 +1912,7 @@ impl Context { name: &str, output: Task, ensure_trailing_newline: bool, - cx: &mut ModelContext, + cx: &mut Context, ) { let version = self.version.clone(); let command_id = InvokedSlashCommandId(self.next_timestamp()); @@ -2184,7 +2180,7 @@ impl Context { fn insert_slash_command_output_section( &mut self, section: SlashCommandOutputSection, - cx: &mut ModelContext, + cx: &mut Context, ) { let buffer = self.buffer.read(cx); let insertion_ix = match self @@ -2214,7 +2210,7 @@ impl Context { &mut self, tool_use_id: LanguageModelToolUseId, output: Task>, - cx: &mut ModelContext, + cx: &mut Context, ) { let insert_output_task = cx.spawn(|this, mut cx| { let tool_use_id = tool_use_id.clone(); @@ -2272,11 +2268,11 @@ impl Context { } } - pub fn completion_provider_changed(&mut self, cx: &mut ModelContext) { + pub fn completion_provider_changed(&mut self, cx: &mut Context) { self.count_remaining_tokens(cx); } - fn get_last_valid_message_id(&self, cx: &ModelContext) -> Option { + fn get_last_valid_message_id(&self, cx: &Context) -> Option { self.message_anchors.iter().rev().find_map(|message| { message .start @@ -2288,7 +2284,7 @@ impl Context { pub fn assist( &mut self, request_type: RequestType, - cx: &mut ModelContext, + cx: &mut Context, ) -> Option { let model_registry = LanguageModelRegistry::read_global(cx); let provider = model_registry.active_provider()?; @@ -2519,7 +2515,7 @@ impl Context { pub fn to_completion_request( &self, request_type: RequestType, - cx: &AppContext, + cx: &App, ) -> LanguageModelRequest { let buffer = self.buffer.read(cx); @@ -2631,7 +2627,7 @@ impl Context { completion_request } - pub fn cancel_last_assist(&mut self, cx: &mut ModelContext) -> bool { + pub fn cancel_last_assist(&mut self, cx: &mut Context) -> bool { if let Some(pending_completion) = self.pending_completions.pop() { self.update_metadata(pending_completion.assistant_message_id, cx, |metadata| { if metadata.status == MessageStatus::Pending { @@ -2644,7 +2640,7 @@ impl Context { } } - pub fn cycle_message_roles(&mut self, ids: HashSet, cx: &mut ModelContext) { + pub fn cycle_message_roles(&mut self, ids: HashSet, cx: &mut Context) { for id in &ids { if let Some(metadata) = self.messages_metadata.get(id) { let role = metadata.role.cycle(); @@ -2655,7 +2651,7 @@ impl Context { self.message_roles_updated(ids, cx); } - fn message_roles_updated(&mut self, ids: HashSet, cx: &mut ModelContext) { + fn message_roles_updated(&mut self, ids: HashSet, cx: &mut Context) { let mut ranges = Vec::new(); for message in self.messages(cx) { if ids.contains(&message.id) { @@ -2678,7 +2674,7 @@ impl Context { pub fn update_metadata( &mut self, id: MessageId, - cx: &mut ModelContext, + cx: &mut Context, f: impl FnOnce(&mut MessageMetadata), ) { let version = self.version.clone(); @@ -2702,7 +2698,7 @@ impl Context { message_id: MessageId, role: Role, status: MessageStatus, - cx: &mut ModelContext, + cx: &mut Context, ) -> Option { if let Some(prev_message_ix) = self .message_anchors @@ -2736,7 +2732,7 @@ impl Context { offset: usize, role: Role, status: MessageStatus, - cx: &mut ModelContext, + cx: &mut Context, ) -> MessageAnchor { let start = self.buffer.update(cx, |buffer, cx| { buffer.edit([(offset..offset, "\n")], None, cx); @@ -2766,7 +2762,7 @@ impl Context { anchor } - pub fn insert_content(&mut self, content: Content, cx: &mut ModelContext) { + pub fn insert_content(&mut self, content: Content, cx: &mut Context) { let buffer = self.buffer.read(cx); let insertion_ix = match self .contents @@ -2782,7 +2778,7 @@ impl Context { cx.emit(ContextEvent::MessagesEdited); } - pub fn contents<'a>(&'a self, cx: &'a AppContext) -> impl 'a + Iterator { + pub fn contents<'a>(&'a self, cx: &'a App) -> impl 'a + Iterator { let buffer = self.buffer.read(cx); self.contents .iter() @@ -2796,7 +2792,7 @@ impl Context { pub fn split_message( &mut self, range: Range, - cx: &mut ModelContext, + cx: &mut Context, ) -> (Option, Option) { let start_message = self.message_for_offset(range.start, cx); let end_message = self.message_for_offset(range.end, cx); @@ -2922,7 +2918,7 @@ impl Context { &mut self, new_anchor: MessageAnchor, new_metadata: MessageMetadata, - cx: &mut ModelContext, + cx: &mut Context, ) { cx.emit(ContextEvent::MessagesEdited); @@ -2940,7 +2936,7 @@ impl Context { self.message_anchors.insert(insertion_ix, new_anchor); } - pub fn summarize(&mut self, replace_old: bool, cx: &mut ModelContext) { + pub fn summarize(&mut self, replace_old: bool, cx: &mut Context) { let Some(provider) = LanguageModelRegistry::read_global(cx).active_provider() else { return; }; @@ -3018,14 +3014,14 @@ impl Context { } } - fn message_for_offset(&self, offset: usize, cx: &AppContext) -> Option { + fn message_for_offset(&self, offset: usize, cx: &App) -> Option { self.messages_for_offsets([offset], cx).pop() } pub fn messages_for_offsets( &self, offsets: impl IntoIterator, - cx: &AppContext, + cx: &App, ) -> Vec { let mut result = Vec::new(); @@ -3058,14 +3054,14 @@ impl Context { fn messages_from_anchors<'a>( &'a self, message_anchors: impl Iterator + 'a, - cx: &'a AppContext, + cx: &'a App, ) -> impl 'a + Iterator { let buffer = self.buffer.read(cx); Self::messages_from_iters(buffer, &self.messages_metadata, message_anchors.enumerate()) } - pub fn messages<'a>(&'a self, cx: &'a AppContext) -> impl 'a + Iterator { + pub fn messages<'a>(&'a self, cx: &'a App) -> impl 'a + Iterator { self.messages_from_anchors(self.message_anchors.iter(), cx) } @@ -3113,7 +3109,7 @@ impl Context { &mut self, debounce: Option, fs: Arc, - cx: &mut ModelContext, + cx: &mut Context, ) { if self.replica_id() != ReplicaId::default() { // Prevent saving a remote context for now. @@ -3179,7 +3175,7 @@ impl Context { }); } - pub fn custom_summary(&mut self, custom_summary: String, cx: &mut ModelContext) { + pub fn custom_summary(&mut self, custom_summary: String, cx: &mut Context) { let timestamp = self.next_timestamp(); let summary = self.summary.get_or_insert(ContextSummary::default()); summary.timestamp = timestamp; @@ -3339,8 +3335,8 @@ impl SavedContext { fn into_ops( self, - buffer: &Model, - cx: &mut ModelContext, + buffer: &Entity, + cx: &mut Context, ) -> Vec { let mut operations = Vec::new(); let mut version = clock::Global::new(); diff --git a/crates/assistant_context_editor/src/context/context_tests.rs b/crates/assistant_context_editor/src/context/context_tests.rs index dcb40f322d..5f433239b2 100644 --- a/crates/assistant_context_editor/src/context/context_tests.rs +++ b/crates/assistant_context_editor/src/context/context_tests.rs @@ -1,5 +1,5 @@ use crate::{ - AssistantEdit, AssistantEditKind, CacheStatus, Context, ContextEvent, ContextId, + AssistantContext, AssistantEdit, AssistantEditKind, CacheStatus, ContextEvent, ContextId, ContextOperation, InvokedSlashCommandId, MessageCacheMetadata, MessageId, MessageStatus, }; use anyhow::Result; @@ -15,7 +15,7 @@ use futures::{ channel::mpsc, stream::{self, StreamExt}, }; -use gpui::{prelude::*, AppContext, Model, SharedString, Task, TestAppContext, WeakView}; +use gpui::{prelude::*, App, Entity, SharedString, Task, TestAppContext, WeakEntity}; use language::{Buffer, BufferSnapshot, LanguageRegistry, LspAdapterDelegate}; use language_model::{LanguageModelCacheConfiguration, LanguageModelRegistry, Role}; use parking_lot::Mutex; @@ -34,7 +34,7 @@ use std::{ sync::{atomic::AtomicBool, Arc}, }; use text::{network::Network, OffsetRangeExt as _, ReplicaId, ToOffset}; -use ui::{IconName, WindowContext}; +use ui::{IconName, Window}; use unindent::Unindent; use util::{ test::{generate_marked_text, marked_text_ranges}, @@ -43,14 +43,14 @@ use util::{ use workspace::Workspace; #[gpui::test] -fn test_inserting_and_removing_messages(cx: &mut AppContext) { +fn test_inserting_and_removing_messages(cx: &mut App) { let settings_store = SettingsStore::test(cx); LanguageModelRegistry::test(cx); cx.set_global(settings_store); let registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone())); let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); - let context = cx.new_model(|cx| { - Context::local( + let context = cx.new(|cx| { + AssistantContext::local( registry, None, None, @@ -183,15 +183,15 @@ fn test_inserting_and_removing_messages(cx: &mut AppContext) { } #[gpui::test] -fn test_message_splitting(cx: &mut AppContext) { +fn test_message_splitting(cx: &mut App) { let settings_store = SettingsStore::test(cx); cx.set_global(settings_store); LanguageModelRegistry::test(cx); let registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone())); let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); - let context = cx.new_model(|cx| { - Context::local( + let context = cx.new(|cx| { + AssistantContext::local( registry.clone(), None, None, @@ -287,14 +287,14 @@ fn test_message_splitting(cx: &mut AppContext) { } #[gpui::test] -fn test_messages_for_offsets(cx: &mut AppContext) { +fn test_messages_for_offsets(cx: &mut App) { let settings_store = SettingsStore::test(cx); LanguageModelRegistry::test(cx); cx.set_global(settings_store); let registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone())); let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); - let context = cx.new_model(|cx| { - Context::local( + let context = cx.new(|cx| { + AssistantContext::local( registry, None, None, @@ -367,9 +367,9 @@ fn test_messages_for_offsets(cx: &mut AppContext) { ); fn message_ids_for_offsets( - context: &Model, + context: &Entity, offsets: &[usize], - cx: &AppContext, + cx: &App, ) -> Vec { context .read(cx) @@ -407,8 +407,8 @@ async fn test_slash_commands(cx: &mut TestAppContext) { let registry = Arc::new(LanguageRegistry::test(cx.executor())); let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); - let context = cx.new_model(|cx| { - Context::local( + let context = cx.new(|cx| { + AssistantContext::local( registry.clone(), None, None, @@ -608,7 +608,7 @@ async fn test_slash_commands(cx: &mut TestAppContext) { #[track_caller] fn assert_text_and_context_ranges( - buffer: &Model, + buffer: &Entity, ranges: &RefCell, expected_marked_text: &str, cx: &mut TestAppContext, @@ -697,8 +697,8 @@ async fn test_workflow_step_parsing(cx: &mut TestAppContext) { // Create a new context let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); - let context = cx.new_model(|cx| { - Context::local( + let context = cx.new(|cx| { + AssistantContext::local( registry.clone(), Some(project), None, @@ -962,8 +962,8 @@ async fn test_workflow_step_parsing(cx: &mut TestAppContext) { // Ensure steps are re-parsed when deserializing. let serialized_context = context.read_with(cx, |context, cx| context.serialize(cx)); - let deserialized_context = cx.new_model(|cx| { - Context::deserialize( + let deserialized_context = cx.new(|cx| { + AssistantContext::deserialize( serialized_context, Default::default(), registry.clone(), @@ -1006,7 +1006,11 @@ async fn test_workflow_step_parsing(cx: &mut TestAppContext) { cx, ); - fn edit(context: &Model, new_text_marked_with_edits: &str, cx: &mut TestAppContext) { + fn edit( + context: &Entity, + new_text_marked_with_edits: &str, + cx: &mut TestAppContext, + ) { context.update(cx, |context, cx| { context.buffer.update(cx, |buffer, cx| { buffer.edit_via_marked_text(&new_text_marked_with_edits.unindent(), None, cx); @@ -1017,7 +1021,7 @@ async fn test_workflow_step_parsing(cx: &mut TestAppContext) { #[track_caller] fn expect_patches( - context: &Model, + context: &Entity, expected_marked_text: &str, expected_suggestions: &[&[AssistantEdit]], cx: &mut TestAppContext, @@ -1077,8 +1081,8 @@ async fn test_serialization(cx: &mut TestAppContext) { cx.update(LanguageModelRegistry::test); let registry = Arc::new(LanguageRegistry::test(cx.executor())); let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); - let context = cx.new_model(|cx| { - Context::local( + let context = cx.new(|cx| { + AssistantContext::local( registry.clone(), None, None, @@ -1121,8 +1125,8 @@ async fn test_serialization(cx: &mut TestAppContext) { ); let serialized_context = context.read_with(cx, |context, cx| context.serialize(cx)); - let deserialized_context = cx.new_model(|cx| { - Context::deserialize( + let deserialized_context = cx.new(|cx| { + AssistantContext::deserialize( serialized_context, Default::default(), registry.clone(), @@ -1179,8 +1183,8 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std let context_id = ContextId::new(); let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); for i in 0..num_peers { - let context = cx.new_model(|cx| { - Context::new( + let context = cx.new(|cx| { + AssistantContext::new( context_id.clone(), i as ReplicaId, language::Capability::ReadWrite, @@ -1434,14 +1438,14 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std } #[gpui::test] -fn test_mark_cache_anchors(cx: &mut AppContext) { +fn test_mark_cache_anchors(cx: &mut App) { let settings_store = SettingsStore::test(cx); LanguageModelRegistry::test(cx); cx.set_global(settings_store); let registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone())); let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap()); - let context = cx.new_model(|cx| { - Context::local( + let context = cx.new(|cx| { + AssistantContext::local( registry, None, None, @@ -1594,7 +1598,7 @@ fn test_mark_cache_anchors(cx: &mut AppContext) { ); } -fn messages(context: &Model, cx: &AppContext) -> Vec<(MessageId, Role, Range)> { +fn messages(context: &Entity, cx: &App) -> Vec<(MessageId, Role, Range)> { context .read(cx) .messages(cx) @@ -1603,8 +1607,8 @@ fn messages(context: &Model, cx: &AppContext) -> Vec<(MessageId, Role, } fn messages_cache( - context: &Model, - cx: &AppContext, + context: &Entity, + cx: &App, ) -> Vec<(MessageId, Option)> { context .read(cx) @@ -1633,8 +1637,9 @@ impl SlashCommand for FakeSlashCommand { self: Arc, _arguments: &[String], _cancel: Arc, - _workspace: Option>, - _cx: &mut WindowContext, + _workspace: Option>, + _window: &mut Window, + _cx: &mut App, ) -> Task>> { Task::ready(Ok(vec![])) } @@ -1648,9 +1653,10 @@ impl SlashCommand for FakeSlashCommand { _arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: BufferSnapshot, - _workspace: WeakView, + _workspace: WeakEntity, _delegate: Option>, - _cx: &mut WindowContext, + _window: &mut Window, + _cx: &mut App, ) -> Task { Task::ready(Ok(SlashCommandOutput { text: format!("Executed fake command: {}", self.0), diff --git a/crates/assistant_context_editor/src/context_editor.rs b/crates/assistant_context_editor/src/context_editor.rs index c22ebeec7d..1db62d9d5b 100644 --- a/crates/assistant_context_editor/src/context_editor.rs +++ b/crates/assistant_context_editor/src/context_editor.rs @@ -23,11 +23,11 @@ use fs::Fs; use futures::FutureExt; use gpui::{ actions, div, img, impl_internal_actions, percentage, point, prelude::*, pulsating_between, - size, Animation, AnimationExt, AnyElement, AnyView, AppContext, AsyncWindowContext, + size, Animation, AnimationExt, AnyElement, AnyView, AnyWindowHandle, App, AsyncWindowContext, ClipboardEntry, ClipboardItem, CursorStyle, Empty, Entity, EventEmitter, FocusHandle, - FocusableView, FontWeight, Global, InteractiveElement, IntoElement, Model, ParentElement, - Pixels, Render, RenderImage, SharedString, Size, StatefulInteractiveElement, Styled, - Subscription, Task, Transformation, View, WeakModel, WeakView, + Focusable, FontWeight, Global, InteractiveElement, IntoElement, ParentElement, Pixels, Render, + RenderImage, SharedString, Size, StatefulInteractiveElement, Styled, Subscription, Task, + Transformation, WeakEntity, }; use indexed_docs::IndexedDocsStore; use language::{language_settings::SoftWrap, BufferSnapshot, LspAdapterDelegate, ToOffset}; @@ -62,9 +62,9 @@ use workspace::{ use crate::{slash_command::SlashCommandCompletionProvider, slash_command_picker}; use crate::{ - AssistantPatch, AssistantPatchStatus, CacheStatus, Content, Context, ContextEvent, ContextId, - InvokedSlashCommandId, InvokedSlashCommandStatus, Message, MessageId, MessageMetadata, - MessageStatus, ParsedSlashCommand, PendingSlashCommandStatus, RequestType, + AssistantContext, AssistantPatch, AssistantPatchStatus, CacheStatus, Content, ContextEvent, + ContextId, InvokedSlashCommandId, InvokedSlashCommandStatus, Message, MessageId, + MessageMetadata, MessageStatus, ParsedSlashCommand, PendingSlashCommandStatus, RequestType, }; actions!( @@ -103,7 +103,7 @@ struct PatchViewState { } struct PatchEditorState { - editor: WeakView, + editor: WeakEntity, opened_patch: AssistantPatch, } @@ -121,40 +121,44 @@ pub trait AssistantPanelDelegate { fn active_context_editor( &self, workspace: &mut Workspace, - cx: &mut ViewContext, - ) -> Option>; + window: &mut Window, + cx: &mut Context, + ) -> Option>; fn open_saved_context( &self, workspace: &mut Workspace, path: PathBuf, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task>; fn open_remote_context( &self, workspace: &mut Workspace, context_id: ContextId, - cx: &mut ViewContext, - ) -> Task>>; + window: &mut Window, + cx: &mut Context, + ) -> Task>>; fn quote_selection( &self, workspace: &mut Workspace, creases: Vec<(String, String)>, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ); } impl dyn AssistantPanelDelegate { /// Returns the global [`AssistantPanelDelegate`], if it exists. - pub fn try_global(cx: &AppContext) -> Option> { + pub fn try_global(cx: &App) -> Option> { cx.try_global::() .map(|global| global.0.clone()) } /// Sets the global [`AssistantPanelDelegate`]. - pub fn set_global(delegate: Arc, cx: &mut AppContext) { + pub fn set_global(delegate: Arc, cx: &mut App) { cx.set_global(GlobalAssistantPanelDelegate(delegate)); } } @@ -164,14 +168,14 @@ struct GlobalAssistantPanelDelegate(Arc); impl Global for GlobalAssistantPanelDelegate {} pub struct ContextEditor { - context: Model, + context: Entity, fs: Arc, slash_commands: Arc, tools: Arc, - workspace: WeakView, - project: Model, + workspace: WeakEntity, + project: Entity, lsp_adapter_delegate: Option>, - editor: View, + editor: Entity, blocks: HashMap, image_blocks: HashSet, scroll_position: Option, @@ -191,7 +195,7 @@ pub struct ContextEditor { // the worktree is not part of the project panel, it would be dropped as soon as // the file is opened. In order to keep the worktree alive for the duration of the // context editor, we keep a reference here. - dragged_file_worktrees: Vec>, + dragged_file_worktrees: Vec>, } pub const DEFAULT_TAB_TITLE: &str = "New Chat"; @@ -199,21 +203,23 @@ const MAX_TAB_TITLE_LEN: usize = 16; impl ContextEditor { pub fn for_context( - context: Model, + context: Entity, fs: Arc, - workspace: WeakView, - project: Model, + workspace: WeakEntity, + project: Entity, lsp_adapter_delegate: Option>, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Self { let completion_provider = SlashCommandCompletionProvider::new( context.read(cx).slash_commands().clone(), - Some(cx.view().downgrade()), + Some(cx.model().downgrade()), Some(workspace.clone()), ); - let editor = cx.new_view(|cx| { - let mut editor = Editor::for_buffer(context.read(cx).buffer().clone(), None, cx); + let editor = cx.new(|cx| { + let mut editor = + Editor::for_buffer(context.read(cx).buffer().clone(), None, window, cx); editor.set_soft_wrap_mode(SoftWrap::EditorWidth, cx); editor.set_show_line_numbers(false, cx); editor.set_show_scrollbars(false, cx); @@ -230,9 +236,9 @@ impl ContextEditor { let _subscriptions = vec![ cx.observe(&context, |_, _, cx| cx.notify()), - cx.subscribe(&context, Self::handle_context_event), - cx.subscribe(&editor, Self::handle_editor_event), - cx.subscribe(&editor, Self::handle_editor_search_event), + cx.subscribe_in(&context, window, Self::handle_context_event), + cx.subscribe_in(&editor, window, Self::handle_editor_event), + cx.subscribe_in(&editor, window, Self::handle_editor_search_event), ]; let sections = context.read(cx).slash_command_output_sections().to_vec(); @@ -265,23 +271,23 @@ impl ContextEditor { }; this.update_message_headers(cx); this.update_image_blocks(cx); - this.insert_slash_command_output_sections(sections, false, cx); - this.patches_updated(&Vec::new(), &patch_ranges, cx); + this.insert_slash_command_output_sections(sections, false, window, cx); + this.patches_updated(&Vec::new(), &patch_ranges, window, cx); this } - pub fn context(&self) -> &Model { + pub fn context(&self) -> &Entity { &self.context } - pub fn editor(&self) -> &View { + pub fn editor(&self) -> &Entity { &self.editor } - pub fn insert_default_prompt(&mut self, cx: &mut ViewContext) { + pub fn insert_default_prompt(&mut self, window: &mut Window, cx: &mut Context) { let command_name = DefaultSlashCommand.name(); self.editor.update(cx, |editor, cx| { - editor.insert(&format!("/{command_name}\n\n"), cx) + editor.insert(&format!("/{command_name}\n\n"), window, cx) }); let command = self.context.update(cx, |context, cx| { context.reparse(cx); @@ -293,26 +299,27 @@ impl ContextEditor { &command.arguments, false, self.workspace.clone(), + window, cx, ); } - fn assist(&mut self, _: &Assist, cx: &mut ViewContext) { - self.send_to_model(RequestType::Chat, cx); + fn assist(&mut self, _: &Assist, window: &mut Window, cx: &mut Context) { + self.send_to_model(RequestType::Chat, window, cx); } - fn edit(&mut self, _: &Edit, cx: &mut ViewContext) { - self.send_to_model(RequestType::SuggestEdits, cx); + fn edit(&mut self, _: &Edit, window: &mut Window, cx: &mut Context) { + self.send_to_model(RequestType::SuggestEdits, window, cx); } - fn focus_active_patch(&mut self, cx: &mut ViewContext) -> bool { + fn focus_active_patch(&mut self, window: &mut Window, cx: &mut Context) -> bool { if let Some((_range, patch)) = self.active_patch() { if let Some(editor) = patch .editor .as_ref() .and_then(|state| state.editor.upgrade()) { - cx.focus_view(&editor); + editor.focus_handle(cx).focus(window); return true; } } @@ -320,7 +327,12 @@ impl ContextEditor { false } - fn send_to_model(&mut self, request_type: RequestType, cx: &mut ViewContext) { + fn send_to_model( + &mut self, + request_type: RequestType, + window: &mut Window, + cx: &mut Context, + ) { let provider = LanguageModelRegistry::read_global(cx).active_provider(); if provider .as_ref() @@ -331,7 +343,7 @@ impl ContextEditor { return; } - if self.focus_active_patch(cx) { + if self.focus_active_patch(window, cx) { return; } @@ -353,18 +365,24 @@ impl ContextEditor { self.editor.update(cx, |editor, cx| { editor.change_selections( Some(Autoscroll::Strategy(AutoscrollStrategy::Fit)), + window, cx, |selections| selections.select_ranges([new_selection]), ); }); // Avoid scrolling to the new cursor position so the assistant's output is stable. - cx.defer(|this, _| this.scroll_position = None); + cx.defer_in(window, |this, _, _| this.scroll_position = None); } cx.notify(); } - fn cancel(&mut self, _: &editor::actions::Cancel, cx: &mut ViewContext) { + fn cancel( + &mut self, + _: &editor::actions::Cancel, + _window: &mut Window, + cx: &mut Context, + ) { self.last_error = None; if self @@ -377,7 +395,12 @@ impl ContextEditor { cx.propagate(); } - fn cycle_message_role(&mut self, _: &CycleMessageRole, cx: &mut ViewContext) { + fn cycle_message_role( + &mut self, + _: &CycleMessageRole, + _window: &mut Window, + cx: &mut Context, + ) { let cursors = self.cursors(cx); self.context.update(cx, |context, cx| { let messages = context @@ -389,7 +412,7 @@ impl ContextEditor { }); } - fn cursors(&self, cx: &mut WindowContext) -> Vec { + fn cursors(&self, cx: &mut App) -> Vec { let selections = self .editor .update(cx, |editor, cx| editor.selections.all::(cx)); @@ -399,11 +422,12 @@ impl ContextEditor { .collect() } - pub fn insert_command(&mut self, name: &str, cx: &mut ViewContext) { + pub fn insert_command(&mut self, name: &str, window: &mut Window, cx: &mut Context) { if let Some(command) = self.slash_commands.command(name, cx) { self.editor.update(cx, |editor, cx| { - editor.transact(cx, |editor, cx| { - editor.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel()); + editor.transact(window, cx, |editor, window, cx| { + editor + .change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel()); let snapshot = editor.buffer().read(cx).snapshot(cx); let newest_cursor = editor.selections.newest::(cx).head(); if newest_cursor.column > 0 @@ -416,25 +440,31 @@ impl ContextEditor { &MoveToEndOfLine { stop_at_soft_wraps: false, }, + window, cx, ); - editor.newline(&Newline, cx); + editor.newline(&Newline, window, cx); } - editor.insert(&format!("/{name}"), cx); + editor.insert(&format!("/{name}"), window, cx); if command.accepts_arguments() { - editor.insert(" ", cx); - editor.show_completions(&ShowCompletions::default(), cx); + editor.insert(" ", window, cx); + editor.show_completions(&ShowCompletions::default(), window, cx); } }); }); if !command.requires_argument() { - self.confirm_command(&ConfirmCommand, cx); + self.confirm_command(&ConfirmCommand, window, cx); } } } - pub fn confirm_command(&mut self, _: &ConfirmCommand, cx: &mut ViewContext) { + pub fn confirm_command( + &mut self, + _: &ConfirmCommand, + window: &mut Window, + cx: &mut Context, + ) { if self.editor.read(cx).has_active_completions_menu() { return; } @@ -465,6 +495,7 @@ impl ContextEditor { &command.arguments, true, workspace.clone(), + window, cx, ); } @@ -479,8 +510,9 @@ impl ContextEditor { name: &str, arguments: &[String], ensure_trailing_newline: bool, - workspace: WeakView, - cx: &mut ViewContext, + workspace: WeakEntity, + window: &mut Window, + cx: &mut Context, ) { if let Some(command) = self.slash_commands.command(name, cx) { let context = self.context.read(cx); @@ -497,6 +529,7 @@ impl ContextEditor { snapshot, workspace, self.lsp_adapter_delegate.clone(), + window, cx, ); self.context.update(cx, |context, cx| { @@ -513,11 +546,12 @@ impl ContextEditor { fn handle_context_event( &mut self, - _: Model, + _: &Entity, event: &ContextEvent, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - let context_editor = cx.view().downgrade(); + let context_editor = cx.model().downgrade(); match event { ContextEvent::MessagesEdited => { @@ -536,12 +570,13 @@ impl ContextEditor { ContextEvent::StreamedCompletion => { self.editor.update(cx, |editor, cx| { if let Some(scroll_position) = self.scroll_position { - let snapshot = editor.snapshot(cx); + let snapshot = editor.snapshot(window, cx); let cursor_point = scroll_position.cursor.to_display_point(&snapshot); let scroll_top = cursor_point.row().as_f32() - scroll_position.offset_before_cursor.y; editor.set_scroll_position( point(scroll_position.offset_before_cursor.x, scroll_top), + window, cx, ); } @@ -570,14 +605,16 @@ impl ContextEditor { .map(|tool_use| { let placeholder = FoldPlaceholder { render: render_fold_icon_button( - cx.view().downgrade(), + cx.model().downgrade(), IconName::PocketKnife, tool_use.name.clone().into(), ), ..Default::default() }; let render_trailer = - move |_row, _unfold, _cx: &mut WindowContext| Empty.into_any(); + move |_row, _unfold, _window: &mut Window, _cx: &mut App| { + Empty.into_any() + }; let start = buffer .anchor_in_excerpt(excerpt_id, tool_use.source_range.start) @@ -615,7 +652,7 @@ impl ContextEditor { let crease_ids = editor.insert_creases(creases, cx); for buffer_row in buffer_rows_to_fold.into_iter().rev() { - editor.fold_at(&FoldAt { buffer_row }, cx); + editor.fold_at(&FoldAt { buffer_row }, window, cx); } self.pending_tool_use_creases.extend( @@ -627,7 +664,7 @@ impl ContextEditor { }); } ContextEvent::PatchesUpdated { removed, updated } => { - self.patches_updated(removed, updated, cx); + self.patches_updated(removed, updated, window, cx); } ContextEvent::ParsedSlashCommandsUpdated { removed, updated } => { self.editor.update(cx, |editor, cx| { @@ -647,7 +684,7 @@ impl ContextEditor { let confirm_command = Arc::new({ let context_editor = context_editor.clone(); let command = command.clone(); - move |cx: &mut WindowContext| { + move |window: &mut Window, cx: &mut App| { context_editor .update(cx, |context_editor, cx| { context_editor.run_command( @@ -656,6 +693,7 @@ impl ContextEditor { &command.arguments, false, workspace.clone(), + window, cx, ); }) @@ -663,13 +701,13 @@ impl ContextEditor { } }); let placeholder = FoldPlaceholder { - render: Arc::new(move |_, _, _| Empty.into_any()), + render: Arc::new(move |_, _, _, _| Empty.into_any()), ..Default::default() }; let render_toggle = { let confirm_command = confirm_command.clone(); let command = command.clone(); - move |row, _, _, _cx: &mut WindowContext| { + move |row, _, _, _window: &mut Window, _cx: &mut App| { render_pending_slash_command_gutter_decoration( row, &command.status, @@ -679,7 +717,7 @@ impl ContextEditor { }; let render_trailer = { let command = command.clone(); - move |row, _unfold, cx: &mut WindowContext| { + move |row, _unfold, _window: &mut Window, cx: &mut App| { // TODO: In the future we should investigate how we can expose // this as a hook on the `SlashCommand` trait so that we don't // need to special-case it here. @@ -715,10 +753,10 @@ impl ContextEditor { }) } ContextEvent::InvokedSlashCommandChanged { command_id } => { - self.update_invoked_slash_command(*command_id, cx); + self.update_invoked_slash_command(*command_id, window, cx); } ContextEvent::SlashCommandOutputSectionAdded { section } => { - self.insert_slash_command_output_sections([section.clone()], false, cx); + self.insert_slash_command_output_sections([section.clone()], false, window, cx); } ContextEvent::UsePendingTools => { let pending_tool_uses = self @@ -732,7 +770,7 @@ impl ContextEditor { for tool_use in pending_tool_uses { if let Some(tool) = self.tools.tool(&tool_use.name, cx) { - let task = tool.run(tool_use.input, self.workspace.clone(), cx); + let task = tool.run(tool_use.input, self.workspace.clone(), window, cx); self.context.update(cx, |context, cx| { context.insert_tool_output(tool_use.id.clone(), task, cx); @@ -751,14 +789,14 @@ impl ContextEditor { let placeholder = FoldPlaceholder { render: render_fold_icon_button( - cx.view().downgrade(), + cx.model().downgrade(), IconName::PocketKnife, format!("Tool Result: {tool_use_id}").into(), ), ..Default::default() }; let render_trailer = - move |_row, _unfold, _cx: &mut WindowContext| Empty.into_any(); + move |_row, _unfold, _window: &mut Window, _cx: &mut App| Empty.into_any(); let start = buffer .anchor_in_excerpt(excerpt_id, output_range.start) @@ -777,7 +815,7 @@ impl ContextEditor { ); editor.insert_creases([crease], cx); - editor.fold_at(&FoldAt { buffer_row }, cx); + editor.fold_at(&FoldAt { buffer_row }, window, cx); }); } ContextEvent::Operation(_) => {} @@ -796,7 +834,8 @@ impl ContextEditor { fn update_invoked_slash_command( &mut self, command_id: InvokedSlashCommandId, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if let Some(invoked_slash_command) = self.context.read(cx).invoked_slash_command(&command_id) @@ -822,6 +861,7 @@ impl ContextEditor { &command.arguments, false, self.workspace.clone(), + window, cx, ); } @@ -872,10 +912,10 @@ impl ContextEditor { crease_start..crease_end, invoked_slash_command_fold_placeholder(command_id, context), fold_toggle("invoked-slash-command"), - |_row, _folded, _cx| Empty.into_any(), + |_row, _folded, _window, _cx| Empty.into_any(), ); let crease_ids = editor.insert_creases([crease.clone()], cx); - editor.fold_creases(vec![crease], false, cx); + editor.fold_creases(vec![crease], false, window, cx); entry.insert(crease_ids[0]); } else { cx.notify() @@ -894,13 +934,14 @@ impl ContextEditor { &mut self, removed: &Vec>, updated: &Vec>, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - let this = cx.view().downgrade(); + let this = cx.model().downgrade(); let mut editors_to_close = Vec::new(); self.editor.update(cx, |editor, cx| { - let snapshot = editor.snapshot(cx); + let snapshot = editor.snapshot(window, cx); let multibuffer = &snapshot.buffer_snapshot; let (&excerpt_id, _, _) = multibuffer.as_singleton().unwrap(); @@ -937,6 +978,7 @@ impl ContextEditor { .unwrap(); let render_block: RenderBlock = Arc::new({ let this = this.clone(); + let window_handle = window.window_handle(); let patch_range = range.clone(); move |cx: &mut BlockContext<'_, '_>| { let max_width = cx.max_width; @@ -950,6 +992,7 @@ impl ContextEditor { gutter_width, block_id, selected, + window_handle, cx, ) }) @@ -973,7 +1016,7 @@ impl ContextEditor { if editor_state.opened_patch != patch { state.update_task = Some({ let this = this.clone(); - cx.spawn(|_, cx| async move { + cx.spawn_in(window, |_, cx| async move { Self::update_patch_editor(this.clone(), patch, cx) .await .log_err(); @@ -1000,23 +1043,24 @@ impl ContextEditor { if should_refold { editor.unfold_ranges(&[patch_start..patch_end], true, false, cx); - editor.fold_creases(vec![crease], false, cx); + editor.fold_creases(vec![crease], false, window, cx); } } }); for editor in editors_to_close { - self.close_patch_editor(editor, cx); + self.close_patch_editor(editor, window, cx); } - self.update_active_patch(cx); + self.update_active_patch(window, cx); } fn insert_slash_command_output_sections( &mut self, sections: impl IntoIterator>, expand_result: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { self.editor.update(cx, |editor, cx| { let buffer = editor.buffer().read(cx).snapshot(cx); @@ -1037,7 +1081,7 @@ impl ContextEditor { start..end, FoldPlaceholder { render: render_fold_icon_button( - cx.view().downgrade(), + cx.model().downgrade(), section.icon, section.label.clone(), ), @@ -1045,7 +1089,7 @@ impl ContextEditor { ..Default::default() }, render_slash_command_output_toggle, - |_, _, _| Empty.into_any_element(), + |_, _, _, _| Empty.into_any_element(), ) .with_metadata(CreaseMetadata { icon: section.icon, @@ -1060,20 +1104,21 @@ impl ContextEditor { buffer_rows_to_fold.clear(); } for buffer_row in buffer_rows_to_fold.into_iter().rev() { - editor.fold_at(&FoldAt { buffer_row }, cx); + editor.fold_at(&FoldAt { buffer_row }, window, cx); } }); } fn handle_editor_event( &mut self, - _: View, + _: &Entity, event: &EditorEvent, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { match event { EditorEvent::ScrollPositionChanged { autoscroll, .. } => { - let cursor_scroll_position = self.cursor_scroll_position(cx); + let cursor_scroll_position = self.cursor_scroll_position(window, cx); if *autoscroll { self.scroll_position = cursor_scroll_position; } else if self.scroll_position != cursor_scroll_position { @@ -1081,8 +1126,8 @@ impl ContextEditor { } } EditorEvent::SelectionsChanged { .. } => { - self.scroll_position = self.cursor_scroll_position(cx); - self.update_active_patch(cx); + self.scroll_position = self.cursor_scroll_position(window, cx); + self.update_active_patch(window, cx); } _ => {} } @@ -1094,7 +1139,7 @@ impl ContextEditor { Some((patch.clone(), self.patches.get(&patch)?)) } - fn update_active_patch(&mut self, cx: &mut ViewContext) { + fn update_active_patch(&mut self, window: &mut Window, cx: &mut Context) { let newest_cursor = self.editor.update(cx, |editor, cx| { editor.selections.newest::(cx).head() }); @@ -1110,7 +1155,7 @@ impl ContextEditor { if let Some(patch_state) = self.patches.get_mut(&old_patch_range) { if let Some(state) = patch_state.editor.take() { if let Some(editor) = state.editor.upgrade() { - self.close_patch_editor(editor, cx); + self.close_patch_editor(editor, window, cx); } } } @@ -1130,13 +1175,14 @@ impl ContextEditor { if let Some(editor) = editor { self.workspace .update(cx, |workspace, cx| { - workspace.activate_item(&editor, true, false, cx); + workspace.activate_item(&editor, true, false, window, cx); }) .ok(); } else { - patch_state.update_task = Some(cx.spawn(move |this, cx| async move { - Self::open_patch_editor(this, new_patch, cx).await.log_err(); - })); + patch_state.update_task = + Some(cx.spawn_in(window, move |this, cx| async move { + Self::open_patch_editor(this, new_patch, cx).await.log_err(); + })); } } } @@ -1144,16 +1190,17 @@ impl ContextEditor { fn close_patch_editor( &mut self, - editor: View, - cx: &mut ViewContext, + editor: Entity, + window: &mut Window, + cx: &mut Context, ) { self.workspace .update(cx, |workspace, cx| { if let Some(pane) = workspace.pane_for(&editor) { pane.update(cx, |pane, cx| { let item_id = editor.entity_id(); - if !editor.read(cx).focus_handle(cx).is_focused(cx) { - pane.close_item_by_id(item_id, SaveIntent::Skip, cx) + if !editor.read(cx).focus_handle(cx).is_focused(window) { + pane.close_item_by_id(item_id, SaveIntent::Skip, window, cx) .detach_and_log_err(cx); } }); @@ -1163,14 +1210,14 @@ impl ContextEditor { } async fn open_patch_editor( - this: WeakView, + this: WeakEntity, patch: AssistantPatch, mut cx: AsyncWindowContext, ) -> Result<()> { let project = this.update(&mut cx, |this, _| this.project.clone())?; let resolved_patch = patch.resolve(project.clone(), &mut cx).await; - let editor = cx.new_view(|cx| { + let editor = cx.new_window_model(|window, cx| { let editor = ProposedChangesEditor::new( patch.title.clone(), resolved_patch @@ -1185,13 +1232,14 @@ impl ContextEditor { }) .collect(), Some(project.clone()), + window, cx, ); resolved_patch.apply(&editor, cx); editor })?; - this.update(&mut cx, |this, cx| { + this.update_in(&mut cx, |this, window, cx| { if let Some(patch_state) = this.patches.get_mut(&patch.range) { patch_state.editor = Some(PatchEditorState { editor: editor.downgrade(), @@ -1202,7 +1250,13 @@ impl ContextEditor { this.workspace .update(cx, |workspace, cx| { - workspace.add_item_to_active_pane(Box::new(editor.clone()), None, false, cx) + workspace.add_item_to_active_pane( + Box::new(editor.clone()), + None, + false, + window, + cx, + ) }) .log_err(); })?; @@ -1211,13 +1265,13 @@ impl ContextEditor { } async fn update_patch_editor( - this: WeakView, + this: WeakEntity, patch: AssistantPatch, mut cx: AsyncWindowContext, ) -> Result<()> { let project = this.update(&mut cx, |this, _| this.project.clone())?; let resolved_patch = patch.resolve(project.clone(), &mut cx).await; - this.update(&mut cx, |this, cx| { + this.update_in(&mut cx, |this, window, cx| { let patch_state = this.patches.get_mut(&patch.range)?; let locations = resolved_patch @@ -1236,7 +1290,7 @@ impl ContextEditor { if let Some(editor) = state.editor.upgrade() { editor.update(cx, |editor, cx| { editor.set_title(patch.title.clone(), cx); - editor.reset_locations(locations, cx); + editor.reset_locations(locations, window, cx); resolved_patch.apply(editor, cx); }); @@ -1254,16 +1308,21 @@ impl ContextEditor { fn handle_editor_search_event( &mut self, - _: View, + _: &Entity, event: &SearchEvent, - cx: &mut ViewContext, + _window: &mut Window, + cx: &mut Context, ) { cx.emit(event.clone()); } - fn cursor_scroll_position(&self, cx: &mut ViewContext) -> Option { + fn cursor_scroll_position( + &self, + window: &mut Window, + cx: &mut Context, + ) -> Option { self.editor.update(cx, |editor, cx| { - let snapshot = editor.snapshot(cx); + let snapshot = editor.snapshot(window, cx); let cursor = editor.selections.newest_anchor().head(); let cursor_row = cursor .to_display_point(&snapshot.display_snapshot) @@ -1286,7 +1345,7 @@ impl ContextEditor { }) } - fn esc_kbd(cx: &WindowContext) -> Div { + fn esc_kbd(cx: &App) -> Div { let colors = cx.theme().colors().clone(); h_flex() @@ -1309,7 +1368,7 @@ impl ContextEditor { .child("to cancel") } - fn update_message_headers(&mut self, cx: &mut ViewContext) { + fn update_message_headers(&mut self, cx: &mut Context) { self.editor.update(cx, |editor, cx| { let buffer = editor.buffer().read(cx).snapshot(cx); @@ -1395,17 +1454,18 @@ impl ContextEditor { .child(label) .children(spinner), ) - .tooltip(|cx| { + .tooltip(|window, cx| { Tooltip::with_meta( "Toggle message role", None, "Available roles: You (User), Assistant, System", + window, cx, ) }) .on_click({ let context = context.clone(); - move |_, cx| { + move |_, _window, cx| { context.update(cx, |context, cx| { context.cycle_message_roles( HashSet::from_iter(Some(message_id)), @@ -1435,11 +1495,12 @@ impl ContextEditor { .size(IconSize::XSmall) .color(Color::Hint), ) - .tooltip(|cx| { + .tooltip(|window, cx| { Tooltip::with_meta( "Context Cached", None, "Large messages cached to optimize performance", + window, cx, ) }) @@ -1467,11 +1528,11 @@ impl ContextEditor { .icon_color(Color::Error) .icon_size(IconSize::XSmall) .icon_position(IconPosition::Start) - .tooltip(move |cx| Tooltip::text("View Details", cx)) + .tooltip(Tooltip::text("View Details")) .on_click({ let context = context.clone(); let error = error.clone(); - move |_, cx| { + move |_, _window, cx| { context.update(cx, |_, cx| { cx.emit(ContextEvent::ShowAssistError( error.clone(), @@ -1552,8 +1613,8 @@ impl ContextEditor { /// Returns either the selected text, or the content of the Markdown code /// block surrounding the cursor. fn get_selection_or_code_block( - context_editor_view: &View, - cx: &mut ViewContext, + context_editor_view: &Entity, + cx: &mut Context, ) -> Option<(String, bool)> { const CODE_FENCE_DELIMITER: &'static str = "```"; @@ -1596,13 +1657,14 @@ impl ContextEditor { pub fn insert_selection( workspace: &mut Workspace, _: &InsertIntoEditor, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let Some(assistant_panel_delegate) = ::try_global(cx) else { return; }; let Some(context_editor_view) = - assistant_panel_delegate.active_context_editor(workspace, cx) + assistant_panel_delegate.active_context_editor(workspace, window, cx) else { return; }; @@ -1615,17 +1677,22 @@ impl ContextEditor { if let Some((text, _)) = Self::get_selection_or_code_block(&context_editor_view, cx) { active_editor_view.update(cx, |editor, cx| { - editor.insert(&text, cx); - editor.focus(cx); + editor.insert(&text, window, cx); + editor.focus_handle(cx).focus(window); }) } } - pub fn copy_code(workspace: &mut Workspace, _: &CopyCode, cx: &mut ViewContext) { + pub fn copy_code( + workspace: &mut Workspace, + _: &CopyCode, + window: &mut Window, + cx: &mut Context, + ) { let result = maybe!({ let assistant_panel_delegate = ::try_global(cx)?; let context_editor_view = - assistant_panel_delegate.active_context_editor(workspace, cx)?; + assistant_panel_delegate.active_context_editor(workspace, window, cx)?; Self::get_selection_or_code_block(&context_editor_view, cx) }); let Some((text, is_code_block)) = result else { @@ -1655,13 +1722,14 @@ impl ContextEditor { pub fn insert_dragged_files( workspace: &mut Workspace, action: &InsertDraggedFiles, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let Some(assistant_panel_delegate) = ::try_global(cx) else { return; }; let Some(context_editor_view) = - assistant_panel_delegate.active_context_editor(workspace, cx) + assistant_panel_delegate.active_context_editor(workspace, window, cx) else { return; }; @@ -1700,38 +1768,40 @@ impl ContextEditor { } }; - cx.spawn(|_, mut cx| async move { - let (paths, dragged_file_worktrees) = paths.await; - let cmd_name = FileSlashCommand.name(); + window + .spawn(cx, |mut cx| async move { + let (paths, dragged_file_worktrees) = paths.await; + let cmd_name = FileSlashCommand.name(); - context_editor_view - .update(&mut cx, |context_editor, cx| { - let file_argument = paths - .into_iter() - .map(|path| path.to_string_lossy().to_string()) - .collect::>() - .join(" "); + context_editor_view + .update_in(&mut cx, |context_editor, window, cx| { + let file_argument = paths + .into_iter() + .map(|path| path.to_string_lossy().to_string()) + .collect::>() + .join(" "); - context_editor.editor.update(cx, |editor, cx| { - editor.insert("\n", cx); - editor.insert(&format!("/{} {}", cmd_name, file_argument), cx); - }); + context_editor.editor.update(cx, |editor, cx| { + editor.insert("\n", window, cx); + editor.insert(&format!("/{} {}", cmd_name, file_argument), window, cx); + }); - context_editor.confirm_command(&ConfirmCommand, cx); + context_editor.confirm_command(&ConfirmCommand, window, cx); - context_editor - .dragged_file_worktrees - .extend(dragged_file_worktrees); - }) - .log_err(); - }) - .detach(); + context_editor + .dragged_file_worktrees + .extend(dragged_file_worktrees); + }) + .log_err(); + }) + .detach(); } pub fn quote_selection( workspace: &mut Workspace, _: &QuoteSelection, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let Some(assistant_panel_delegate) = ::try_global(cx) else { return; @@ -1745,17 +1815,22 @@ impl ContextEditor { return; } - assistant_panel_delegate.quote_selection(workspace, creases, cx); + assistant_panel_delegate.quote_selection(workspace, creases, window, cx); } - pub fn quote_creases(&mut self, creases: Vec<(String, String)>, cx: &mut ViewContext) { + pub fn quote_creases( + &mut self, + creases: Vec<(String, String)>, + window: &mut Window, + cx: &mut Context, + ) { self.editor.update(cx, |editor, cx| { - editor.insert("\n", cx); + editor.insert("\n", window, cx); for (text, crease_title) in creases { let point = editor.selections.newest::(cx).head(); let start_row = MultiBufferRow(point.row); - editor.insert(&text, cx); + editor.insert(&text, window, cx); let snapshot = editor.buffer().read(cx).snapshot(cx); let anchor_before = snapshot.anchor_after(point); @@ -1765,28 +1840,29 @@ impl ContextEditor { .head() .bias_left(&snapshot); - editor.insert("\n", cx); + editor.insert("\n", window, cx); let fold_placeholder = - quote_selection_fold_placeholder(crease_title, cx.view().downgrade()); + quote_selection_fold_placeholder(crease_title, cx.model().downgrade()); let crease = Crease::inline( anchor_before..anchor_after, fold_placeholder, render_quote_selection_output_toggle, - |_, _, _| Empty.into_any(), + |_, _, _, _| Empty.into_any(), ); editor.insert_creases(vec![crease], cx); editor.fold_at( &FoldAt { buffer_row: start_row, }, + window, cx, ); } }) } - fn copy(&mut self, _: &editor::actions::Copy, cx: &mut ViewContext) { + fn copy(&mut self, _: &editor::actions::Copy, _window: &mut Window, cx: &mut Context) { if self.editor.read(cx).selections.count() == 1 { let (copied_text, metadata, _) = self.get_clipboard_contents(cx); cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata( @@ -1800,16 +1876,16 @@ impl ContextEditor { cx.propagate(); } - fn cut(&mut self, _: &editor::actions::Cut, cx: &mut ViewContext) { + fn cut(&mut self, _: &editor::actions::Cut, window: &mut Window, cx: &mut Context) { if self.editor.read(cx).selections.count() == 1 { let (copied_text, metadata, selections) = self.get_clipboard_contents(cx); self.editor.update(cx, |editor, cx| { - editor.transact(cx, |this, cx| { - this.change_selections(Some(Autoscroll::fit()), cx, |s| { + editor.transact(window, cx, |this, window, cx| { + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select(selections); }); - this.insert("", cx); + this.insert("", window, cx); cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata( copied_text, metadata, @@ -1826,7 +1902,7 @@ impl ContextEditor { fn get_clipboard_contents( &mut self, - cx: &mut ViewContext, + cx: &mut Context, ) -> (String, CopyMetadata, Vec>) { let (snapshot, selection, creases) = self.editor.update(cx, |editor, cx| { let mut selection = editor.selections.newest::(cx); @@ -1908,7 +1984,12 @@ impl ContextEditor { (text, CopyMetadata { creases }, vec![selection]) } - fn paste(&mut self, action: &editor::actions::Paste, cx: &mut ViewContext) { + fn paste( + &mut self, + action: &editor::actions::Paste, + window: &mut Window, + cx: &mut Context, + ) { cx.stop_propagation(); let images = if let Some(item) = cx.read_from_clipboard() { @@ -1940,13 +2021,13 @@ impl ContextEditor { if images.is_empty() { self.editor.update(cx, |editor, cx| { let paste_position = editor.selections.newest::(cx).head(); - editor.paste(action, cx); + editor.paste(action, window, cx); if let Some(metadata) = metadata { let buffer = editor.buffer().read(cx).snapshot(cx); let mut buffer_rows_to_fold = BTreeSet::new(); - let weak_editor = cx.view().downgrade(); + let weak_editor = cx.model().downgrade(); editor.insert_creases( metadata.creases.into_iter().map(|metadata| { let start = buffer.anchor_after( @@ -1969,21 +2050,21 @@ impl ContextEditor { ..Default::default() }, render_slash_command_output_toggle, - |_, _, _| Empty.into_any(), + |_, _, _, _| Empty.into_any(), ) .with_metadata(metadata.crease.clone()) }), cx, ); for buffer_row in buffer_rows_to_fold.into_iter().rev() { - editor.fold_at(&FoldAt { buffer_row }, cx); + editor.fold_at(&FoldAt { buffer_row }, window, cx); } } }); } else { let mut image_positions = Vec::new(); self.editor.update(cx, |editor, cx| { - editor.transact(cx, |editor, cx| { + editor.transact(window, cx, |editor, _window, cx| { let edits = editor .selections .all::(cx) @@ -2023,7 +2104,7 @@ impl ContextEditor { } } - fn update_image_blocks(&mut self, cx: &mut ViewContext) { + fn update_image_blocks(&mut self, cx: &mut Context) { self.editor.update(cx, |editor, cx| { let buffer = editor.buffer().read(cx).snapshot(cx); let excerpt_id = *buffer.as_singleton().unwrap().0; @@ -2081,7 +2162,7 @@ impl ContextEditor { }); } - fn split(&mut self, _: &Split, cx: &mut ViewContext) { + fn split(&mut self, _: &Split, _window: &mut Window, cx: &mut Context) { self.context.update(cx, |context, cx| { let selections = self.editor.read(cx).selections.disjoint_anchors(); for selection in selections.as_ref() { @@ -2094,13 +2175,13 @@ impl ContextEditor { }); } - fn save(&mut self, _: &Save, cx: &mut ViewContext) { + fn save(&mut self, _: &Save, _window: &mut Window, cx: &mut Context) { self.context.update(cx, |context, cx| { context.save(Some(Duration::from_millis(500)), self.fs.clone(), cx) }); } - pub fn title(&self, cx: &AppContext) -> Cow { + pub fn title(&self, cx: &App) -> Cow { self.context .read(cx) .summary() @@ -2109,6 +2190,7 @@ impl ContextEditor { .unwrap_or_else(|| Cow::Borrowed(DEFAULT_TAB_TITLE)) } + #[allow(clippy::too_many_arguments)] fn render_patch_block( &mut self, range: Range, @@ -2116,9 +2198,15 @@ impl ContextEditor { gutter_width: Pixels, id: BlockId, selected: bool, - cx: &mut ViewContext, + window_handle: AnyWindowHandle, + cx: &mut Context, ) -> Option { - let snapshot = self.editor.update(cx, |editor, cx| editor.snapshot(cx)); + let snapshot = window_handle + .update(cx, |_, window, cx| { + self.editor + .update(cx, |editor, cx| editor.snapshot(window, cx)) + }) + .ok()?; let (excerpt_id, _buffer_id, _) = snapshot.buffer_snapshot.as_singleton().unwrap(); let excerpt_id = *excerpt_id; let anchor = snapshot @@ -2149,13 +2237,13 @@ impl ContextEditor { this.border_color(theme.colors().text_accent) }) .cursor(CursorStyle::PointingHand) - .on_click(cx.listener(move |this, _, cx| { + .on_click(cx.listener(move |this, _, window, cx| { this.editor.update(cx, |editor, cx| { - editor.change_selections(None, cx, |selections| { + editor.change_selections(None, window, cx, |selections| { selections.select_ranges(vec![anchor..anchor]); }); }); - this.focus_active_patch(cx); + this.focus_active_patch(window, cx); })) .child( div() @@ -2218,7 +2306,7 @@ impl ContextEditor { ) } - fn render_notice(&self, cx: &mut ViewContext) -> Option { + fn render_notice(&self, cx: &mut Context) -> Option { // This was previously gated behind the `zed-pro` feature flag. Since we // aren't planning to ship that right now, we're just hard-coding this // value to not show the nudge. @@ -2242,7 +2330,7 @@ impl ContextEditor { Button::new("sign-in", "Sign in") .size(ButtonSize::Compact) .style(ButtonStyle::Filled) - .on_click(cx.listener(|this, _event, cx| { + .on_click(cx.listener(|this, _event, _window, cx| { let client = this .workspace .update(cx, |workspace, _| workspace.client().clone()) @@ -2294,8 +2382,8 @@ impl ContextEditor { .style(ButtonStyle::Filled) .on_click({ let focus_handle = self.focus_handle(cx).clone(); - move |_event, cx| { - focus_handle.dispatch_action(&ShowConfiguration, cx); + move |_event, window, cx| { + focus_handle.dispatch_action(&ShowConfiguration, window, cx); } }), ) @@ -2306,13 +2394,13 @@ impl ContextEditor { } } - fn render_send_button(&self, cx: &mut ViewContext) -> impl IntoElement { + fn render_send_button(&self, window: &mut Window, cx: &mut Context) -> impl IntoElement { let focus_handle = self.focus_handle(cx).clone(); let (style, tooltip) = match token_state(&self.context, cx) { Some(TokenState::NoTokensLeft { .. }) => ( ButtonStyle::Tinted(TintColor::Error), - Some(Tooltip::text("Token limit reached", cx)), + Some(Tooltip::text("Token limit reached")(window, cx)), ), Some(TokenState::HasMoreTokens { over_warn_threshold, @@ -2321,7 +2409,9 @@ impl ContextEditor { let (style, tooltip) = if over_warn_threshold { ( ButtonStyle::Tinted(TintColor::Warning), - Some(Tooltip::text("Token limit is close to exhaustion", cx)), + Some(Tooltip::text("Token limit is close to exhaustion")( + window, cx, + )), ) } else { (ButtonStyle::Filled, None) @@ -2344,7 +2434,7 @@ impl ContextEditor { .disabled(disabled) .style(style) .when_some(tooltip, |button, tooltip| { - button.tooltip(move |_| tooltip.clone()) + button.tooltip(move |_, _| tooltip.clone()) }) .layer(ElevationIndex::ModalSurface) .child(Label::new( @@ -2355,21 +2445,21 @@ impl ContextEditor { }, )) .children( - KeyBinding::for_action_in(&Assist, &focus_handle, cx) + KeyBinding::for_action_in(&Assist, &focus_handle, window) .map(|binding| binding.into_any_element()), ) - .on_click(move |_event, cx| { - focus_handle.dispatch_action(&Assist, cx); + .on_click(move |_event, window, cx| { + focus_handle.dispatch_action(&Assist, window, cx); }) } - fn render_edit_button(&self, cx: &mut ViewContext) -> impl IntoElement { + fn render_edit_button(&self, window: &mut Window, cx: &mut Context) -> impl IntoElement { let focus_handle = self.focus_handle(cx).clone(); let (style, tooltip) = match token_state(&self.context, cx) { Some(TokenState::NoTokensLeft { .. }) => ( ButtonStyle::Tinted(TintColor::Error), - Some(Tooltip::text("Token limit reached", cx)), + Some(Tooltip::text("Token limit reached")(window, cx)), ), Some(TokenState::HasMoreTokens { over_warn_threshold, @@ -2378,7 +2468,9 @@ impl ContextEditor { let (style, tooltip) = if over_warn_threshold { ( ButtonStyle::Tinted(TintColor::Warning), - Some(Tooltip::text("Token limit is close to exhaustion", cx)), + Some(Tooltip::text("Token limit is close to exhaustion")( + window, cx, + )), ) } else { (ButtonStyle::Filled, None) @@ -2401,33 +2493,33 @@ impl ContextEditor { .disabled(disabled) .style(style) .when_some(tooltip, |button, tooltip| { - button.tooltip(move |_| tooltip.clone()) + button.tooltip(move |_, _| tooltip.clone()) }) .layer(ElevationIndex::ModalSurface) .child(Label::new("Suggest Edits")) .children( - KeyBinding::for_action_in(&Edit, &focus_handle, cx) + KeyBinding::for_action_in(&Edit, &focus_handle, window) .map(|binding| binding.into_any_element()), ) - .on_click(move |_event, cx| { - focus_handle.dispatch_action(&Edit, cx); + .on_click(move |_event, window, cx| { + focus_handle.dispatch_action(&Edit, window, cx); }) } - fn render_inject_context_menu(&self, cx: &mut ViewContext) -> impl IntoElement { + fn render_inject_context_menu(&self, cx: &mut Context) -> impl IntoElement { slash_command_picker::SlashCommandSelector::new( self.slash_commands.clone(), - cx.view().downgrade(), + cx.model().downgrade(), Button::new("trigger", "Add Context") .icon(IconName::Plus) .icon_size(IconSize::Small) .icon_color(Color::Muted) .icon_position(IconPosition::Start) - .tooltip(|cx| Tooltip::text("Type / to insert via keyboard", cx)), + .tooltip(Tooltip::text("Type / to insert via keyboard")), ) } - fn render_last_error(&self, cx: &mut ViewContext) -> Option { + fn render_last_error(&self, cx: &mut Context) -> Option { let last_error = self.last_error.as_ref()?; Some( @@ -2454,7 +2546,7 @@ impl ContextEditor { ) } - fn render_file_required_error(&self, cx: &mut ViewContext) -> AnyElement { + fn render_file_required_error(&self, cx: &mut Context) -> AnyElement { v_flex() .gap_0p5() .child( @@ -2480,7 +2572,7 @@ impl ContextEditor { .justify_end() .mt_1() .child(Button::new("dismiss", "Dismiss").on_click(cx.listener( - |this, _, cx| { + |this, _, _window, cx| { this.last_error = None; cx.notify(); }, @@ -2489,7 +2581,7 @@ impl ContextEditor { .into_any() } - fn render_payment_required_error(&self, cx: &mut ViewContext) -> AnyElement { + fn render_payment_required_error(&self, cx: &mut Context) -> AnyElement { const ERROR_MESSAGE: &str = "Free tier exceeded. Subscribe and add payment to continue using Zed LLMs. You'll be billed at cost for tokens used."; v_flex() @@ -2513,14 +2605,14 @@ impl ContextEditor { .justify_end() .mt_1() .child(Button::new("subscribe", "Subscribe").on_click(cx.listener( - |this, _, cx| { + |this, _, _window, cx| { this.last_error = None; cx.open_url(&zed_urls::account_url(cx)); cx.notify(); }, ))) .child(Button::new("dismiss", "Dismiss").on_click(cx.listener( - |this, _, cx| { + |this, _, _window, cx| { this.last_error = None; cx.notify(); }, @@ -2529,7 +2621,7 @@ impl ContextEditor { .into_any() } - fn render_max_monthly_spend_reached_error(&self, cx: &mut ViewContext) -> AnyElement { + fn render_max_monthly_spend_reached_error(&self, cx: &mut Context) -> AnyElement { const ERROR_MESSAGE: &str = "You have reached your maximum monthly spend. Increase your spend limit to continue using Zed LLMs."; v_flex() @@ -2554,7 +2646,7 @@ impl ContextEditor { .mt_1() .child( Button::new("subscribe", "Update Monthly Spend Limit").on_click( - cx.listener(|this, _, cx| { + cx.listener(|this, _, _window, cx| { this.last_error = None; cx.open_url(&zed_urls::account_url(cx)); cx.notify(); @@ -2562,7 +2654,7 @@ impl ContextEditor { ), ) .child(Button::new("dismiss", "Dismiss").on_click(cx.listener( - |this, _, cx| { + |this, _, _window, cx| { this.last_error = None; cx.notify(); }, @@ -2574,7 +2666,7 @@ impl ContextEditor { fn render_assist_error( &self, error_message: &SharedString, - cx: &mut ViewContext, + cx: &mut Context, ) -> AnyElement { v_flex() .gap_0p5() @@ -2600,7 +2692,7 @@ impl ContextEditor { .justify_end() .mt_1() .child(Button::new("dismiss", "Dismiss").on_click(cx.listener( - |this, _, cx| { + |this, _, _window, cx| { this.last_error = None; cx.notify(); }, @@ -2653,25 +2745,25 @@ fn find_surrounding_code_block(snapshot: &BufferSnapshot, offset: usize) -> Opti } fn render_fold_icon_button( - editor: WeakView, + editor: WeakEntity, icon: IconName, label: SharedString, -) -> Arc, &mut WindowContext) -> AnyElement> { - Arc::new(move |fold_id, fold_range, _cx| { +) -> Arc, &mut Window, &mut App) -> AnyElement> { + Arc::new(move |fold_id, fold_range, _window, _cx| { let editor = editor.clone(); ButtonLike::new(fold_id) .style(ButtonStyle::Filled) .layer(ElevationIndex::ElevatedSurface) .child(Icon::new(icon)) .child(Label::new(label.clone()).single_line()) - .on_click(move |_, cx| { + .on_click(move |_, window, cx| { editor .update(cx, |editor, cx| { let buffer_start = fold_range .start .to_point(&editor.buffer().read(cx).read(cx)); let buffer_row = MultiBufferRow(buffer_start.row); - editor.unfold_at(&UnfoldAt { buffer_row }, cx); + editor.unfold_at(&UnfoldAt { buffer_row }, window, cx); }) .ok(); }) @@ -2679,20 +2771,21 @@ fn render_fold_icon_button( }) } -type ToggleFold = Arc; +type ToggleFold = Arc; fn render_slash_command_output_toggle( row: MultiBufferRow, is_folded: bool, fold: ToggleFold, - _cx: &mut WindowContext, + _window: &mut Window, + _cx: &mut App, ) -> AnyElement { Disclosure::new( ("slash-command-output-fold-indicator", row.0 as u64), !is_folded, ) .toggle_state(is_folded) - .on_click(move |_e, cx| fold(!is_folded, cx)) + .on_click(move |_e, window, cx| fold(!is_folded, window, cx)) .into_any_element() } @@ -2701,35 +2794,36 @@ pub fn fold_toggle( ) -> impl Fn( MultiBufferRow, bool, - Arc, - &mut WindowContext, + Arc, + &mut Window, + &mut App, ) -> AnyElement { - move |row, is_folded, fold, _cx| { + move |row, is_folded, fold, _window, _cx| { Disclosure::new((name, row.0 as u64), !is_folded) .toggle_state(is_folded) - .on_click(move |_e, cx| fold(!is_folded, cx)) + .on_click(move |_e, window, cx| fold(!is_folded, window, cx)) .into_any_element() } } -fn quote_selection_fold_placeholder(title: String, editor: WeakView) -> FoldPlaceholder { +fn quote_selection_fold_placeholder(title: String, editor: WeakEntity) -> FoldPlaceholder { FoldPlaceholder { render: Arc::new({ - move |fold_id, fold_range, _cx| { + move |fold_id, fold_range, _window, _cx| { let editor = editor.clone(); ButtonLike::new(fold_id) .style(ButtonStyle::Filled) .layer(ElevationIndex::ElevatedSurface) .child(Icon::new(IconName::TextSnippet)) .child(Label::new(title.clone()).single_line()) - .on_click(move |_, cx| { + .on_click(move |_, window, cx| { editor .update(cx, |editor, cx| { let buffer_start = fold_range .start .to_point(&editor.buffer().read(cx).read(cx)); let buffer_row = MultiBufferRow(buffer_start.row); - editor.unfold_at(&UnfoldAt { buffer_row }, cx); + editor.unfold_at(&UnfoldAt { buffer_row }, window, cx); }) .ok(); }) @@ -2745,24 +2839,25 @@ fn render_quote_selection_output_toggle( row: MultiBufferRow, is_folded: bool, fold: ToggleFold, - _cx: &mut WindowContext, + _window: &mut Window, + _cx: &mut App, ) -> AnyElement { Disclosure::new(("quote-selection-indicator", row.0 as u64), !is_folded) .toggle_state(is_folded) - .on_click(move |_e, cx| fold(!is_folded, cx)) + .on_click(move |_e, window, cx| fold(!is_folded, window, cx)) .into_any_element() } fn render_pending_slash_command_gutter_decoration( row: MultiBufferRow, status: &PendingSlashCommandStatus, - confirm_command: Arc, + confirm_command: Arc, ) -> AnyElement { let mut icon = IconButton::new( ("slash-command-gutter-decoration", row.0), ui::IconName::TriangleRight, ) - .on_click(move |_e, cx| confirm_command(cx)) + .on_click(move |_e, window, cx| confirm_command(window, cx)) .icon_size(ui::IconSize::Small) .size(ui::ButtonSize::None); @@ -2782,7 +2877,7 @@ fn render_pending_slash_command_gutter_decoration( fn render_docs_slash_command_trailer( row: MultiBufferRow, command: ParsedSlashCommand, - cx: &mut WindowContext, + cx: &mut App, ) -> AnyElement { if command.arguments.is_empty() { return Empty.into_any(); @@ -2813,7 +2908,7 @@ fn render_docs_slash_command_trailer( )) .tooltip({ let package = package.clone(); - move |cx| Tooltip::text(format!("Indexing {package}…"), cx) + Tooltip::text(format!("Indexing {package}…")) }) .into_any_element(), ); @@ -2828,7 +2923,7 @@ fn render_docs_slash_command_trailer( .size(IconSize::Small) .color(Color::Warning), ) - .tooltip(move |cx| Tooltip::text(format!("Failed to index: {latest_error}"), cx)) + .tooltip(Tooltip::text(format!("Failed to index: {latest_error}"))) .into_any_element(), ) } @@ -2858,7 +2953,7 @@ impl EventEmitter for ContextEditor {} impl EventEmitter for ContextEditor {} impl Render for ContextEditor { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { let provider = LanguageModelRegistry::read_global(cx).active_provider(); let accept_terms = if self.show_accept_terms { provider.as_ref().and_then(|provider| { @@ -2923,7 +3018,7 @@ impl Render for ContextEditor { buttons .items_center() .gap_1p5() - .child(self.render_edit_button(cx)) + .child(self.render_edit_button(window, cx)) .child( Label::new("or") .size(LabelSize::Small) @@ -2931,15 +3026,15 @@ impl Render for ContextEditor { ) }, ) - .child(self.render_send_button(cx)), + .child(self.render_send_button(window, cx)), ), ), ) } } -impl FocusableView for ContextEditor { - fn focus_handle(&self, cx: &AppContext) -> FocusHandle { +impl Focusable for ContextEditor { + fn focus_handle(&self, cx: &App) -> FocusHandle { self.editor.focus_handle(cx) } } @@ -2947,7 +3042,7 @@ impl FocusableView for ContextEditor { impl Item for ContextEditor { type Event = editor::EditorEvent; - fn tab_content_text(&self, cx: &WindowContext) -> Option { + fn tab_content_text(&self, _window: &Window, cx: &App) -> Option { Some(util::truncate_and_trailoff(&self.title(cx), MAX_TAB_TITLE_LEN).into()) } @@ -2963,34 +3058,45 @@ impl Item for ContextEditor { } } - fn tab_tooltip_text(&self, cx: &AppContext) -> Option { + fn tab_tooltip_text(&self, cx: &App) -> Option { Some(self.title(cx).to_string().into()) } - fn as_searchable(&self, handle: &View) -> Option> { + fn as_searchable(&self, handle: &Entity) -> Option> { Some(Box::new(handle.clone())) } - fn set_nav_history(&mut self, nav_history: pane::ItemNavHistory, cx: &mut ViewContext) { + fn set_nav_history( + &mut self, + nav_history: pane::ItemNavHistory, + window: &mut Window, + cx: &mut Context, + ) { self.editor.update(cx, |editor, cx| { - Item::set_nav_history(editor, nav_history, cx) + Item::set_nav_history(editor, nav_history, window, cx) }) } - fn navigate(&mut self, data: Box, cx: &mut ViewContext) -> bool { + fn navigate( + &mut self, + data: Box, + window: &mut Window, + cx: &mut Context, + ) -> bool { self.editor - .update(cx, |editor, cx| Item::navigate(editor, data, cx)) + .update(cx, |editor, cx| Item::navigate(editor, data, window, cx)) } - fn deactivated(&mut self, cx: &mut ViewContext) { - self.editor.update(cx, Item::deactivated) + fn deactivated(&mut self, window: &mut Window, cx: &mut Context) { + self.editor + .update(cx, |editor, cx| Item::deactivated(editor, window, cx)) } fn act_as_type<'a>( &'a self, type_id: TypeId, - self_handle: &'a View, - _: &'a AppContext, + self_handle: &'a Entity, + _: &'a App, ) -> Option { if type_id == TypeId::of::() { Some(self_handle.to_any()) @@ -3009,64 +3115,80 @@ impl Item for ContextEditor { impl SearchableItem for ContextEditor { type Match = ::Match; - fn clear_matches(&mut self, cx: &mut ViewContext) { + fn clear_matches(&mut self, window: &mut Window, cx: &mut Context) { self.editor.update(cx, |editor, cx| { - editor.clear_matches(cx); + editor.clear_matches(window, cx); }); } - fn update_matches(&mut self, matches: &[Self::Match], cx: &mut ViewContext) { + fn update_matches( + &mut self, + matches: &[Self::Match], + window: &mut Window, + cx: &mut Context, + ) { self.editor - .update(cx, |editor, cx| editor.update_matches(matches, cx)); + .update(cx, |editor, cx| editor.update_matches(matches, window, cx)); } - fn query_suggestion(&mut self, cx: &mut ViewContext) -> String { + fn query_suggestion(&mut self, window: &mut Window, cx: &mut Context) -> String { self.editor - .update(cx, |editor, cx| editor.query_suggestion(cx)) + .update(cx, |editor, cx| editor.query_suggestion(window, cx)) } fn activate_match( &mut self, index: usize, matches: &[Self::Match], - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { self.editor.update(cx, |editor, cx| { - editor.activate_match(index, matches, cx); + editor.activate_match(index, matches, window, cx); }); } - fn select_matches(&mut self, matches: &[Self::Match], cx: &mut ViewContext) { + fn select_matches( + &mut self, + matches: &[Self::Match], + window: &mut Window, + cx: &mut Context, + ) { self.editor - .update(cx, |editor, cx| editor.select_matches(matches, cx)); + .update(cx, |editor, cx| editor.select_matches(matches, window, cx)); } fn replace( &mut self, identifier: &Self::Match, query: &project::search::SearchQuery, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.editor - .update(cx, |editor, cx| editor.replace(identifier, query, cx)); + self.editor.update(cx, |editor, cx| { + editor.replace(identifier, query, window, cx) + }); } fn find_matches( &mut self, query: Arc, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { self.editor - .update(cx, |editor, cx| editor.find_matches(query, cx)) + .update(cx, |editor, cx| editor.find_matches(query, window, cx)) } fn active_match_index( &mut self, matches: &[Self::Match], - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Option { - self.editor - .update(cx, |editor, cx| editor.active_match_index(matches, cx)) + self.editor.update(cx, |editor, cx| { + editor.active_match_index(matches, window, cx) + }) } } @@ -3075,13 +3197,13 @@ impl FollowableItem for ContextEditor { self.remote_id } - fn to_state_proto(&self, cx: &WindowContext) -> Option { + fn to_state_proto(&self, window: &Window, cx: &App) -> Option { let context = self.context.read(cx); Some(proto::view::Variant::ContextEditor( proto::view::ContextEditor { context_id: context.id().to_proto(), editor: if let Some(proto::view::Variant::Editor(proto)) = - self.editor.read(cx).to_state_proto(cx) + self.editor.read(cx).to_state_proto(window, cx) { Some(proto) } else { @@ -3092,11 +3214,12 @@ impl FollowableItem for ContextEditor { } fn from_state_proto( - workspace: View, + workspace: Entity, id: workspace::ViewId, state: &mut Option, - cx: &mut WindowContext, - ) -> Option>>> { + window: &mut Window, + cx: &mut App, + ) -> Option>>> { let proto::view::Variant::ContextEditor(_) = state.as_ref()? else { return None; }; @@ -3111,13 +3234,13 @@ impl FollowableItem for ContextEditor { let assistant_panel_delegate = ::try_global(cx)?; let context_editor_task = workspace.update(cx, |workspace, cx| { - assistant_panel_delegate.open_remote_context(workspace, context_id, cx) + assistant_panel_delegate.open_remote_context(workspace, context_id, window, cx) }); - Some(cx.spawn(|mut cx| async move { + Some(window.spawn(cx, |mut cx| async move { let context_editor = context_editor_task.await?; context_editor - .update(&mut cx, |context_editor, cx| { + .update_in(&mut cx, |context_editor, window, cx| { context_editor.remote_id = Some(id); context_editor.editor.update(cx, |editor, cx| { editor.apply_update_proto( @@ -3130,6 +3253,7 @@ impl FollowableItem for ContextEditor { scroll_y: editor_state.scroll_y, ..Default::default() }), + window, cx, ) }) @@ -3147,39 +3271,42 @@ impl FollowableItem for ContextEditor { &self, event: &Self::Event, update: &mut Option, - cx: &WindowContext, + window: &Window, + cx: &App, ) -> bool { self.editor .read(cx) - .add_event_to_update_proto(event, update, cx) + .add_event_to_update_proto(event, update, window, cx) } fn apply_update_proto( &mut self, - project: &Model, + project: &Entity, message: proto::update_view::Variant, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { self.editor.update(cx, |editor, cx| { - editor.apply_update_proto(project, message, cx) + editor.apply_update_proto(project, message, window, cx) }) } - fn is_project_item(&self, _cx: &WindowContext) -> bool { + fn is_project_item(&self, _window: &Window, _cx: &App) -> bool { true } fn set_leader_peer_id( &mut self, leader_peer_id: Option, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { self.editor.update(cx, |editor, cx| { - editor.set_leader_peer_id(leader_peer_id, cx) + editor.set_leader_peer_id(leader_peer_id, window, cx) }) } - fn dedup(&self, existing: &Self, cx: &WindowContext) -> Option { + fn dedup(&self, existing: &Self, _window: &Window, cx: &App) -> Option { if existing.context.read(cx).id() == self.context.read(cx).id() { Some(item::Dedup::KeepExisting) } else { @@ -3189,9 +3316,9 @@ impl FollowableItem for ContextEditor { } pub struct ContextEditorToolbarItem { - active_context_editor: Option>, - model_summary_editor: View, - language_model_selector: View, + active_context_editor: Option>, + model_summary_editor: Entity, + language_model_selector: Entity, language_model_selector_menu_handle: PopoverMenuHandle, } @@ -3199,13 +3326,14 @@ impl ContextEditorToolbarItem { pub fn new( workspace: &Workspace, model_selector_menu_handle: PopoverMenuHandle, - model_summary_editor: View, - cx: &mut ViewContext, + model_summary_editor: Entity, + window: &mut Window, + cx: &mut Context, ) -> Self { Self { active_context_editor: None, model_summary_editor, - language_model_selector: cx.new_view(|cx| { + language_model_selector: cx.new(|cx| { let fs = workspace.app_state().fs.clone(); LanguageModelSelector::new( move |model, cx| { @@ -3215,6 +3343,7 @@ impl ContextEditorToolbarItem { move |settings, _| settings.set_model(model.clone()), ); }, + window, cx, ) }), @@ -3222,7 +3351,7 @@ impl ContextEditorToolbarItem { } } - fn render_remaining_tokens(&self, cx: &mut ViewContext) -> Option { + fn render_remaining_tokens(&self, cx: &mut Context) -> Option { let context = &self .active_context_editor .as_ref()? @@ -3266,7 +3395,7 @@ impl ContextEditorToolbarItem { } impl Render for ContextEditorToolbarItem { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { let left_side = h_flex() .group("chat-title-group") .gap_1() @@ -3283,8 +3412,8 @@ impl Render for ContextEditorToolbarItem { div().visible_on_hover("chat-title-group").child( IconButton::new("regenerate-context", IconName::RefreshTitle) .shape(ui::IconButtonShape::Square) - .tooltip(|cx| Tooltip::text("Regenerate Title", cx)) - .on_click(cx.listener(move |_, _, cx| { + .tooltip(Tooltip::text("Regenerate Title")) + .on_click(cx.listener(move |_, _, _window, cx| { cx.emit(ContextEditorToolbarItemEvent::RegenerateSummary) })), ), @@ -3350,8 +3479,8 @@ impl Render for ContextEditorToolbarItem { .size(IconSize::XSmall), ), ) - .tooltip(move |cx| { - Tooltip::for_action("Change Model", &ToggleModelSelector, cx) + .tooltip(move |window, cx| { + Tooltip::for_action("Change Model", &ToggleModelSelector, window, cx) }), ) .with_handle(self.language_model_selector_menu_handle.clone()), @@ -3372,7 +3501,8 @@ impl ToolbarItemView for ContextEditorToolbarItem { fn set_active_pane_item( &mut self, active_pane_item: Option<&dyn ItemHandle>, - cx: &mut ViewContext, + _window: &mut Window, + cx: &mut Context, ) -> ToolbarItemLocation { self.active_context_editor = active_pane_item .and_then(|item| item.act_as::(cx)) @@ -3385,7 +3515,12 @@ impl ToolbarItemView for ContextEditorToolbarItem { } } - fn pane_focus_update(&mut self, _pane_focused: bool, cx: &mut ViewContext) { + fn pane_focus_update( + &mut self, + _pane_focused: bool, + _window: &mut Window, + cx: &mut Context, + ) { cx.notify(); } } @@ -3401,12 +3536,12 @@ enum PendingSlashCommand {} fn invoked_slash_command_fold_placeholder( command_id: InvokedSlashCommandId, - context: WeakModel, + context: WeakEntity, ) -> FoldPlaceholder { FoldPlaceholder { constrain_width: false, merge_adjacent: false, - render: Arc::new(move |fold_id, _, cx| { + render: Arc::new(move |fold_id, _, _window, cx| { let Some(context) = context.upgrade() else { return Empty.into_any(); }; @@ -3456,7 +3591,7 @@ enum TokenState { }, } -fn token_state(context: &Model, cx: &AppContext) -> Option { +fn token_state(context: &Entity, cx: &App) -> Option { const WARNING_TOKEN_THRESHOLD: f32 = 0.8; let model = LanguageModelRegistry::read_global(cx).active_model()?; @@ -3511,7 +3646,7 @@ pub enum ConfigurationError { ProviderPendingTermsAcceptance(Arc), } -fn configuration_error(cx: &AppContext) -> Option { +fn configuration_error(cx: &App) -> Option { let provider = LanguageModelRegistry::read_global(cx).active_provider(); let is_authenticated = provider .as_ref() @@ -3551,8 +3686,8 @@ pub fn humanize_token_count(count: usize) -> String { } pub fn make_lsp_adapter_delegate( - project: &Model, - cx: &mut AppContext, + project: &Entity, + cx: &mut App, ) -> Result>> { project.update(cx, |project, cx| { // TODO: Find the right worktree. @@ -3577,15 +3712,15 @@ pub fn make_lsp_adapter_delegate( #[cfg(test)] mod tests { use super::*; - use gpui::{AppContext, Context}; + use gpui::App; use language::Buffer; use unindent::Unindent; #[gpui::test] - fn test_find_code_blocks(cx: &mut AppContext) { + fn test_find_code_blocks(cx: &mut App) { let markdown = languages::language("markdown", tree_sitter_md::LANGUAGE.into()); - let buffer = cx.new_model(|cx| { + let buffer = cx.new(|cx| { let text = r#" line 0 line 1 diff --git a/crates/assistant_context_editor/src/context_history.rs b/crates/assistant_context_editor/src/context_history.rs index c6dac32a07..2401f6d70b 100644 --- a/crates/assistant_context_editor/src/context_history.rs +++ b/crates/assistant_context_editor/src/context_history.rs @@ -1,8 +1,6 @@ use std::sync::Arc; -use gpui::{ - AppContext, EventEmitter, FocusHandle, FocusableView, Model, Subscription, Task, View, WeakView, -}; +use gpui::{App, Entity, EventEmitter, FocusHandle, Focusable, Subscription, Task, WeakEntity}; use picker::{Picker, PickerDelegate}; use project::Project; use ui::utils::{format_distance_from_now, DateTimeType}; @@ -25,21 +23,23 @@ enum SavedContextPickerEvent { } pub struct ContextHistory { - picker: View>, + picker: Entity>, _subscriptions: Vec, - workspace: WeakView, + workspace: WeakEntity, } impl ContextHistory { pub fn new( - project: Model, - context_store: Model, - workspace: WeakView, - cx: &mut ViewContext, + project: Entity, + context_store: Entity, + workspace: WeakEntity, + window: &mut Window, + cx: &mut Context, ) -> Self { - let picker = cx.new_view(|cx| { + let picker = cx.new(|cx| { Picker::uniform_list( SavedContextPickerDelegate::new(project, context_store.clone()), + window, cx, ) .modal(false) @@ -47,10 +47,11 @@ impl ContextHistory { }); let subscriptions = vec![ - cx.observe(&context_store, |this, _, cx| { - this.picker.update(cx, |picker, cx| picker.refresh(cx)); + cx.observe_in(&context_store, window, |this, _, window, cx| { + this.picker + .update(cx, |picker, cx| picker.refresh(window, cx)); }), - cx.subscribe(&picker, Self::handle_picker_event), + cx.subscribe_in(&picker, window, Self::handle_picker_event), ]; Self { @@ -62,9 +63,10 @@ impl ContextHistory { fn handle_picker_event( &mut self, - _: View>, + _: &Entity>, event: &SavedContextPickerEvent, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let SavedContextPickerEvent::Confirmed(context) = event; @@ -76,12 +78,12 @@ impl ContextHistory { .update(cx, |workspace, cx| match context { ContextMetadata::Remote(metadata) => { assistant_panel_delegate - .open_remote_context(workspace, metadata.id.clone(), cx) + .open_remote_context(workspace, metadata.id.clone(), window, cx) .detach_and_log_err(cx); } ContextMetadata::Saved(metadata) => { assistant_panel_delegate - .open_saved_context(workspace, metadata.path.clone(), cx) + .open_saved_context(workspace, metadata.path.clone(), window, cx) .detach_and_log_err(cx); } }) @@ -90,13 +92,13 @@ impl ContextHistory { } impl Render for ContextHistory { - fn render(&mut self, _: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { div().size_full().child(self.picker.clone()) } } -impl FocusableView for ContextHistory { - fn focus_handle(&self, cx: &AppContext) -> FocusHandle { +impl Focusable for ContextHistory { + fn focus_handle(&self, cx: &App) -> FocusHandle { self.picker.focus_handle(cx) } } @@ -106,14 +108,14 @@ impl EventEmitter<()> for ContextHistory {} impl Item for ContextHistory { type Event = (); - fn tab_content_text(&self, _cx: &WindowContext) -> Option { + fn tab_content_text(&self, _window: &Window, _cx: &App) -> Option { Some("History".into()) } } struct SavedContextPickerDelegate { - store: Model, - project: Model, + store: Entity, + project: Entity, matches: Vec, selected_index: usize, } @@ -121,7 +123,7 @@ struct SavedContextPickerDelegate { impl EventEmitter for Picker {} impl SavedContextPickerDelegate { - fn new(project: Model, store: Model) -> Self { + fn new(project: Entity, store: Entity) -> Self { Self { project, store, @@ -142,15 +144,25 @@ impl PickerDelegate for SavedContextPickerDelegate { self.selected_index } - fn set_selected_index(&mut self, ix: usize, _cx: &mut ViewContext>) { + fn set_selected_index( + &mut self, + ix: usize, + _window: &mut Window, + _cx: &mut Context>, + ) { self.selected_index = ix; } - fn placeholder_text(&self, _cx: &mut WindowContext) -> Arc { + fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc { "Search...".into() } - fn update_matches(&mut self, query: String, cx: &mut ViewContext>) -> Task<()> { + fn update_matches( + &mut self, + query: String, + _window: &mut Window, + cx: &mut Context>, + ) -> Task<()> { let search = self.store.read(cx).search(query, cx); cx.spawn(|this, mut cx| async move { let matches = search.await; @@ -169,19 +181,20 @@ impl PickerDelegate for SavedContextPickerDelegate { }) } - fn confirm(&mut self, _secondary: bool, cx: &mut ViewContext>) { + fn confirm(&mut self, _secondary: bool, _window: &mut Window, cx: &mut Context>) { if let Some(metadata) = self.matches.get(self.selected_index) { cx.emit(SavedContextPickerEvent::Confirmed(metadata.clone())); } } - fn dismissed(&mut self, _cx: &mut ViewContext>) {} + fn dismissed(&mut self, _window: &mut Window, _cx: &mut Context>) {} fn render_match( &self, ix: usize, selected: bool, - cx: &mut ViewContext>, + _window: &mut Window, + cx: &mut Context>, ) -> Option { let context = self.matches.get(ix)?; let item = match context { diff --git a/crates/assistant_context_editor/src/context_store.rs b/crates/assistant_context_editor/src/context_store.rs index 7b1b8c7d4c..9a852bb3d9 100644 --- a/crates/assistant_context_editor/src/context_store.rs +++ b/crates/assistant_context_editor/src/context_store.rs @@ -1,5 +1,5 @@ use crate::{ - Context, ContextEvent, ContextId, ContextOperation, ContextVersion, SavedContext, + AssistantContext, ContextEvent, ContextId, ContextOperation, ContextVersion, SavedContext, SavedContextMetadata, }; use anyhow::{anyhow, Context as _, Result}; @@ -14,7 +14,7 @@ use fs::Fs; use futures::StreamExt; use fuzzy::StringMatchCandidate; use gpui::{ - AppContext, AsyncAppContext, Context as _, EventEmitter, Model, ModelContext, Task, WeakModel, + App, AppContext as _, AsyncAppContext, Context, Entity, EventEmitter, Task, WeakEntity, }; use language::LanguageRegistry; use paths::contexts_dir; @@ -50,7 +50,7 @@ pub struct RemoteContextMetadata { pub struct ContextStore { contexts: Vec, contexts_metadata: Vec, - context_server_manager: Model, + context_server_manager: Entity, context_server_slash_command_ids: HashMap, Vec>, context_server_tool_ids: HashMap, Vec>, host_contexts: Vec, @@ -61,7 +61,7 @@ pub struct ContextStore { telemetry: Arc, _watch_updates: Task>, client: Arc, - project: Model, + project: Entity, project_is_shared: bool, client_subscription: Option, _project_subscriptions: Vec, @@ -75,19 +75,19 @@ pub enum ContextStoreEvent { impl EventEmitter for ContextStore {} enum ContextHandle { - Weak(WeakModel), - Strong(Model), + Weak(WeakEntity), + Strong(Entity), } impl ContextHandle { - fn upgrade(&self) -> Option> { + fn upgrade(&self) -> Option> { match self { ContextHandle::Weak(weak) => weak.upgrade(), ContextHandle::Strong(strong) => Some(strong.clone()), } } - fn downgrade(&self) -> WeakModel { + fn downgrade(&self) -> WeakEntity { match self { ContextHandle::Weak(weak) => weak.clone(), ContextHandle::Strong(strong) => strong.downgrade(), @@ -97,12 +97,12 @@ impl ContextHandle { impl ContextStore { pub fn new( - project: Model, + project: Entity, prompt_builder: Arc, slash_commands: Arc, tools: Arc, - cx: &mut AppContext, - ) -> Task>> { + cx: &mut App, + ) -> Task>> { let fs = project.read(cx).fs().clone(); let languages = project.read(cx).languages().clone(); let telemetry = project.read(cx).client().telemetry().clone(); @@ -110,10 +110,10 @@ impl ContextStore { const CONTEXT_WATCH_DURATION: Duration = Duration::from_millis(100); let (mut events, _) = fs.watch(contexts_dir(), CONTEXT_WATCH_DURATION).await; - let this = cx.new_model(|cx: &mut ModelContext| { + let this = cx.new(|cx: &mut Context| { let context_server_factory_registry = ContextServerFactoryRegistry::default_global(cx); - let context_server_manager = cx.new_model(|cx| { + let context_server_manager = cx.new(|cx| { ContextServerManager::new(context_server_factory_registry, project.clone(), cx) }); let mut this = Self { @@ -163,7 +163,7 @@ impl ContextStore { } async fn handle_advertise_contexts( - this: Model, + this: Entity, envelope: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result<()> { @@ -182,7 +182,7 @@ impl ContextStore { } async fn handle_open_context( - this: Model, + this: Entity, envelope: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result { @@ -212,7 +212,7 @@ impl ContextStore { } async fn handle_create_context( - this: Model, + this: Entity, _: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result { @@ -240,7 +240,7 @@ impl ContextStore { } async fn handle_update_context( - this: Model, + this: Entity, envelope: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result<()> { @@ -256,7 +256,7 @@ impl ContextStore { } async fn handle_synchronize_contexts( - this: Model, + this: Entity, envelope: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result { @@ -299,7 +299,7 @@ impl ContextStore { })? } - fn handle_project_changed(&mut self, _: Model, cx: &mut ModelContext) { + fn handle_project_changed(&mut self, _: Entity, cx: &mut Context) { let is_shared = self.project.read(cx).is_shared(); let was_shared = mem::replace(&mut self.project_is_shared, is_shared); if is_shared == was_shared { @@ -320,7 +320,7 @@ impl ContextStore { .client .subscribe_to_entity(remote_id) .log_err() - .map(|subscription| subscription.set_model(&cx.handle(), &mut cx.to_async())); + .map(|subscription| subscription.set_model(&cx.model(), &mut cx.to_async())); self.advertise_contexts(cx); } else { self.client_subscription = None; @@ -329,9 +329,9 @@ impl ContextStore { fn handle_project_event( &mut self, - _: Model, + _: Entity, event: &project::Event, - cx: &mut ModelContext, + cx: &mut Context, ) { match event { project::Event::Reshared => { @@ -361,9 +361,9 @@ impl ContextStore { } } - pub fn create(&mut self, cx: &mut ModelContext) -> Model { - let context = cx.new_model(|cx| { - Context::local( + pub fn create(&mut self, cx: &mut Context) -> Entity { + let context = cx.new(|cx| { + AssistantContext::local( self.languages.clone(), Some(self.project.clone()), Some(self.telemetry.clone()), @@ -379,8 +379,8 @@ impl ContextStore { pub fn create_remote_context( &mut self, - cx: &mut ModelContext, - ) -> Task>> { + cx: &mut Context, + ) -> Task>> { let project = self.project.read(cx); let Some(project_id) = project.remote_id() else { return Task::ready(Err(anyhow!("project was not remote"))); @@ -399,8 +399,8 @@ impl ContextStore { let response = request.await?; let context_id = ContextId::from_proto(response.context_id); let context_proto = response.context.context("invalid context")?; - let context = cx.new_model(|cx| { - Context::new( + let context = cx.new(|cx| { + AssistantContext::new( context_id.clone(), replica_id, capability, @@ -439,8 +439,8 @@ impl ContextStore { pub fn open_local_context( &mut self, path: PathBuf, - cx: &ModelContext, - ) -> Task>> { + cx: &Context, + ) -> Task>> { if let Some(existing_context) = self.loaded_context_for_path(&path, cx) { return Task::ready(Ok(existing_context)); } @@ -462,8 +462,8 @@ impl ContextStore { cx.spawn(|this, mut cx| async move { let saved_context = load.await?; - let context = cx.new_model(|cx| { - Context::deserialize( + let context = cx.new(|cx| { + AssistantContext::deserialize( saved_context, path.clone(), languages, @@ -486,7 +486,7 @@ impl ContextStore { }) } - fn loaded_context_for_path(&self, path: &Path, cx: &AppContext) -> Option> { + fn loaded_context_for_path(&self, path: &Path, cx: &App) -> Option> { self.contexts.iter().find_map(|context| { let context = context.upgrade()?; if context.read(cx).path() == Some(path) { @@ -497,7 +497,11 @@ impl ContextStore { }) } - pub fn loaded_context_for_id(&self, id: &ContextId, cx: &AppContext) -> Option> { + pub fn loaded_context_for_id( + &self, + id: &ContextId, + cx: &App, + ) -> Option> { self.contexts.iter().find_map(|context| { let context = context.upgrade()?; if context.read(cx).id() == id { @@ -511,8 +515,8 @@ impl ContextStore { pub fn open_remote_context( &mut self, context_id: ContextId, - cx: &mut ModelContext, - ) -> Task>> { + cx: &mut Context, + ) -> Task>> { let project = self.project.read(cx); let Some(project_id) = project.remote_id() else { return Task::ready(Err(anyhow!("project was not remote"))); @@ -537,8 +541,8 @@ impl ContextStore { cx.spawn(|this, mut cx| async move { let response = request.await?; let context_proto = response.context.context("invalid context")?; - let context = cx.new_model(|cx| { - Context::new( + let context = cx.new(|cx| { + AssistantContext::new( context_id.clone(), replica_id, capability, @@ -574,7 +578,7 @@ impl ContextStore { }) } - fn register_context(&mut self, context: &Model, cx: &mut ModelContext) { + fn register_context(&mut self, context: &Entity, cx: &mut Context) { let handle = if self.project_is_shared { ContextHandle::Strong(context.clone()) } else { @@ -587,9 +591,9 @@ impl ContextStore { fn handle_context_event( &mut self, - context: Model, + context: Entity, event: &ContextEvent, - cx: &mut ModelContext, + cx: &mut Context, ) { let Some(project_id) = self.project.read(cx).remote_id() else { return; @@ -614,7 +618,7 @@ impl ContextStore { } } - fn advertise_contexts(&self, cx: &AppContext) { + fn advertise_contexts(&self, cx: &App) { let Some(project_id) = self.project.read(cx).remote_id() else { return; }; @@ -648,7 +652,7 @@ impl ContextStore { .ok(); } - fn synchronize_contexts(&mut self, cx: &mut ModelContext) { + fn synchronize_contexts(&mut self, cx: &mut Context) { let Some(project_id) = self.project.read(cx).remote_id() else { return; }; @@ -703,7 +707,7 @@ impl ContextStore { .detach_and_log_err(cx); } - pub fn search(&self, query: String, cx: &AppContext) -> Task> { + pub fn search(&self, query: String, cx: &App) -> Task> { let metadata = self.contexts_metadata.clone(); let executor = cx.background_executor().clone(); cx.background_executor().spawn(async move { @@ -737,7 +741,7 @@ impl ContextStore { &self.host_contexts } - fn reload(&mut self, cx: &mut ModelContext) -> Task> { + fn reload(&mut self, cx: &mut Context) -> Task> { let fs = self.fs.clone(); cx.spawn(|this, mut cx| async move { fs.create_dir(contexts_dir()).await?; @@ -786,7 +790,7 @@ impl ContextStore { }) } - pub fn restart_context_servers(&mut self, cx: &mut ModelContext) { + pub fn restart_context_servers(&mut self, cx: &mut Context) { cx.update_model( &self.context_server_manager, |context_server_manager, cx| { @@ -799,7 +803,7 @@ impl ContextStore { ); } - fn register_context_server_handlers(&self, cx: &mut ModelContext) { + fn register_context_server_handlers(&self, cx: &mut Context) { cx.subscribe( &self.context_server_manager.clone(), Self::handle_context_server_event, @@ -809,9 +813,9 @@ impl ContextStore { fn handle_context_server_event( &mut self, - context_server_manager: Model, + context_server_manager: Entity, event: &context_server::manager::Event, - cx: &mut ModelContext, + cx: &mut Context, ) { let slash_command_working_set = self.slash_commands.clone(); let tool_working_set = self.tools.clone(); diff --git a/crates/assistant_context_editor/src/patch.rs b/crates/assistant_context_editor/src/patch.rs index dbb9fb2b8f..bbad1880c6 100644 --- a/crates/assistant_context_editor/src/patch.rs +++ b/crates/assistant_context_editor/src/patch.rs @@ -2,7 +2,7 @@ use anyhow::{anyhow, Context as _, Result}; use collections::HashMap; use editor::ProposedChangesEditor; use futures::{future, TryFutureExt as _}; -use gpui::{AppContext, AsyncAppContext, Model, SharedString}; +use gpui::{App, AsyncAppContext, Entity, SharedString}; use language::{AutoindentMode, Buffer, BufferSnapshot}; use project::{Project, ProjectPath}; use std::{cmp, ops::Range, path::Path, sync::Arc}; @@ -56,7 +56,7 @@ pub enum AssistantEditKind { #[derive(Clone, Debug, Eq, PartialEq)] pub struct ResolvedPatch { - pub edit_groups: HashMap, Vec>, + pub edit_groups: HashMap, Vec>, pub errors: Vec, } @@ -121,7 +121,7 @@ impl SearchMatrix { } impl ResolvedPatch { - pub fn apply(&self, editor: &ProposedChangesEditor, cx: &mut AppContext) { + pub fn apply(&self, editor: &ProposedChangesEditor, cx: &mut App) { for (buffer, groups) in &self.edit_groups { let branch = editor.branch_buffer_for_base(buffer).unwrap(); Self::apply_edit_groups(groups, &branch, cx); @@ -129,11 +129,7 @@ impl ResolvedPatch { editor.recalculate_all_buffer_diffs(); } - fn apply_edit_groups( - groups: &Vec, - buffer: &Model, - cx: &mut AppContext, - ) { + fn apply_edit_groups(groups: &Vec, buffer: &Entity, cx: &mut App) { let mut edits = Vec::new(); for group in groups { for suggestion in &group.edits { @@ -232,9 +228,9 @@ impl AssistantEdit { pub async fn resolve( &self, - project: Model, + project: Entity, mut cx: AsyncAppContext, - ) -> Result<(Model, ResolvedEdit)> { + ) -> Result<(Entity, ResolvedEdit)> { let path = self.path.clone(); let kind = self.kind.clone(); let buffer = project @@ -427,7 +423,7 @@ impl AssistantEditKind { impl AssistantPatch { pub async fn resolve( &self, - project: Model, + project: Entity, cx: &mut AsyncAppContext, ) -> ResolvedPatch { let mut resolve_tasks = Vec::new(); @@ -555,7 +551,7 @@ impl Eq for AssistantPatch {} #[cfg(test)] mod tests { use super::*; - use gpui::{AppContext, Context}; + use gpui::{App, AppContext as _}; use language::{ language_settings::AllLanguageSettings, Language, LanguageConfig, LanguageMatcher, }; @@ -565,7 +561,7 @@ mod tests { use util::test::{generate_marked_text, marked_text_ranges}; #[gpui::test] - fn test_resolve_location(cx: &mut AppContext) { + fn test_resolve_location(cx: &mut App) { assert_location_resolution( concat!( " Lorem\n", @@ -636,7 +632,7 @@ mod tests { } #[gpui::test] - fn test_resolve_edits(cx: &mut AppContext) { + fn test_resolve_edits(cx: &mut App) { init_test(cx); assert_edits( @@ -902,7 +898,7 @@ mod tests { ); } - fn init_test(cx: &mut AppContext) { + fn init_test(cx: &mut App) { let settings_store = SettingsStore::test(cx); cx.set_global(settings_store); language::init(cx); @@ -912,13 +908,9 @@ mod tests { } #[track_caller] - fn assert_location_resolution( - text_with_expected_range: &str, - query: &str, - cx: &mut AppContext, - ) { + fn assert_location_resolution(text_with_expected_range: &str, query: &str, cx: &mut App) { let (text, _) = marked_text_ranges(text_with_expected_range, false); - let buffer = cx.new_model(|cx| Buffer::local(text.clone(), cx)); + let buffer = cx.new(|cx| Buffer::local(text.clone(), cx)); let snapshot = buffer.read(cx).snapshot(); let range = AssistantEditKind::resolve_location(&snapshot, query).to_offset(&snapshot); let text_with_actual_range = generate_marked_text(&text, &[range], false); @@ -930,10 +922,10 @@ mod tests { old_text: String, edits: Vec, new_text: String, - cx: &mut AppContext, + cx: &mut App, ) { let buffer = - cx.new_model(|cx| Buffer::local(old_text, cx).with_language(Arc::new(rust_lang()), cx)); + cx.new(|cx| Buffer::local(old_text, cx).with_language(Arc::new(rust_lang()), cx)); let snapshot = buffer.read(cx).snapshot(); let resolved_edits = edits .into_iter() diff --git a/crates/assistant_context_editor/src/slash_command.rs b/crates/assistant_context_editor/src/slash_command.rs index d00b3a41a9..6cecc9470c 100644 --- a/crates/assistant_context_editor/src/slash_command.rs +++ b/crates/assistant_context_editor/src/slash_command.rs @@ -4,7 +4,7 @@ pub use assistant_slash_command::SlashCommand; use assistant_slash_command::{AfterCompletion, SlashCommandLine, SlashCommandWorkingSet}; use editor::{CompletionProvider, Editor}; use fuzzy::{match_strings, StringMatchCandidate}; -use gpui::{Model, Task, ViewContext, WeakView, WindowContext}; +use gpui::{App, Context, Entity, Task, WeakEntity, Window}; use language::{Anchor, Buffer, Documentation, LanguageServerId, ToPoint}; use parking_lot::Mutex; use project::CompletionIntent; @@ -23,15 +23,15 @@ use workspace::Workspace; pub struct SlashCommandCompletionProvider { cancel_flag: Mutex>, slash_commands: Arc, - editor: Option>, - workspace: Option>, + editor: Option>, + workspace: Option>, } impl SlashCommandCompletionProvider { pub fn new( slash_commands: Arc, - editor: Option>, - workspace: Option>, + editor: Option>, + workspace: Option>, ) -> Self { Self { cancel_flag: Mutex::new(Arc::new(AtomicBool::new(false))), @@ -46,7 +46,8 @@ impl SlashCommandCompletionProvider { command_name: &str, command_range: Range, name_range: Range, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Task>> { let slash_commands = self.slash_commands.clone(); let candidates = slash_commands @@ -58,7 +59,7 @@ impl SlashCommandCompletionProvider { let command_name = command_name.to_string(); let editor = self.editor.clone(); let workspace = self.workspace.clone(); - cx.spawn(|mut cx| async move { + window.spawn(cx, |mut cx| async move { let matches = match_strings( &candidates, &command_name, @@ -69,7 +70,7 @@ impl SlashCommandCompletionProvider { ) .await; - cx.update(|cx| { + cx.update(|_, cx| { matches .into_iter() .filter_map(|mat| { @@ -91,28 +92,31 @@ impl SlashCommandCompletionProvider { let editor = editor.clone(); let workspace = workspace.clone(); Arc::new( - move |intent: CompletionIntent, cx: &mut WindowContext| { - if !requires_argument - && (!accepts_arguments || intent.is_complete()) - { - editor - .update(cx, |editor, cx| { - editor.run_command( - command_range.clone(), - &command_name, - &[], - true, - workspace.clone(), - cx, - ); - }) - .ok(); - false - } else { - requires_argument || accepts_arguments - } - }, - ) as Arc<_> + move |intent: CompletionIntent, + window: &mut Window, + cx: &mut App| { + if !requires_argument + && (!accepts_arguments || intent.is_complete()) + { + editor + .update(cx, |editor, cx| { + editor.run_command( + command_range.clone(), + &command_name, + &[], + true, + workspace.clone(), + window, + cx, + ); + }) + .ok(); + false + } else { + requires_argument || accepts_arguments + } + }, + ) as Arc<_> }); Some(project::Completion { old_range: name_range.clone(), @@ -130,6 +134,7 @@ impl SlashCommandCompletionProvider { }) } + #[allow(clippy::too_many_arguments)] fn complete_command_argument( &self, command_name: &str, @@ -137,7 +142,8 @@ impl SlashCommandCompletionProvider { command_range: Range, argument_range: Range, last_argument_range: Range, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Task>> { let new_cancel_flag = Arc::new(AtomicBool::new(false)); let mut flag = self.cancel_flag.lock(); @@ -148,6 +154,7 @@ impl SlashCommandCompletionProvider { arguments, new_cancel_flag.clone(), self.workspace.clone(), + window, cx, ); let command_name: Arc = command_name.into(); @@ -175,7 +182,9 @@ impl SlashCommandCompletionProvider { let command_range = command_range.clone(); let command_name = command_name.clone(); - move |intent: CompletionIntent, cx: &mut WindowContext| { + move |intent: CompletionIntent, + window: &mut Window, + cx: &mut App| { if new_argument.after_completion.run() || intent.is_complete() { @@ -187,6 +196,7 @@ impl SlashCommandCompletionProvider { &completed_arguments, true, workspace.clone(), + window, cx, ); }) @@ -230,10 +240,11 @@ impl SlashCommandCompletionProvider { impl CompletionProvider for SlashCommandCompletionProvider { fn completions( &self, - buffer: &Model, + buffer: &Entity, buffer_position: Anchor, _: editor::CompletionContext, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task>> { let Some((name, arguments, command_range, last_argument_range)) = buffer.update(cx, |buffer, _cx| { @@ -288,30 +299,31 @@ impl CompletionProvider for SlashCommandCompletionProvider { command_range, argument_range, last_argument_range, + window, cx, ) } else { - self.complete_command_name(&name, command_range, last_argument_range, cx) + self.complete_command_name(&name, command_range, last_argument_range, window, cx) } } fn resolve_completions( &self, - _: Model, + _: Entity, _: Vec, _: Rc>>, - _: &mut ViewContext, + _: &mut Context, ) -> Task> { Task::ready(Ok(true)) } fn is_completion_trigger( &self, - buffer: &Model, + buffer: &Entity, position: language::Anchor, _text: &str, _trigger_in_words: bool, - cx: &mut ViewContext, + cx: &mut Context, ) -> bool { let buffer = buffer.read(cx); let position = position.to_point(buffer); diff --git a/crates/assistant_context_editor/src/slash_command_picker.rs b/crates/assistant_context_editor/src/slash_command_picker.rs index c8911636d0..373e5f09dd 100644 --- a/crates/assistant_context_editor/src/slash_command_picker.rs +++ b/crates/assistant_context_editor/src/slash_command_picker.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use assistant_slash_command::SlashCommandWorkingSet; -use gpui::{AnyElement, DismissEvent, SharedString, Task, WeakView}; +use gpui::{AnyElement, DismissEvent, SharedString, Task, WeakEntity}; use picker::{Picker, PickerDelegate, PickerEditorPosition}; use ui::{prelude::*, ListItem, ListItemSpacing, PopoverMenu, PopoverTrigger, Tooltip}; @@ -10,7 +10,7 @@ use crate::context_editor::ContextEditor; #[derive(IntoElement)] pub(super) struct SlashCommandSelector { working_set: Arc, - active_context_editor: WeakView, + active_context_editor: WeakEntity, trigger: T, } @@ -27,8 +27,8 @@ enum SlashCommandEntry { Info(SlashCommandInfo), Advert { name: SharedString, - renderer: fn(&mut WindowContext) -> AnyElement, - on_confirm: fn(&mut WindowContext), + renderer: fn(&mut Window, &mut App) -> AnyElement, + on_confirm: fn(&mut Window, &mut App), }, } @@ -44,14 +44,14 @@ impl AsRef for SlashCommandEntry { pub(crate) struct SlashCommandDelegate { all_commands: Vec, filtered_commands: Vec, - active_context_editor: WeakView, + active_context_editor: WeakEntity, selected_index: usize, } impl SlashCommandSelector { pub(crate) fn new( working_set: Arc, - active_context_editor: WeakView, + active_context_editor: WeakEntity, trigger: T, ) -> Self { SlashCommandSelector { @@ -73,18 +73,23 @@ impl PickerDelegate for SlashCommandDelegate { self.selected_index } - fn set_selected_index(&mut self, ix: usize, cx: &mut ViewContext>) { + fn set_selected_index(&mut self, ix: usize, _: &mut Window, cx: &mut Context>) { self.selected_index = ix.min(self.filtered_commands.len().saturating_sub(1)); cx.notify(); } - fn placeholder_text(&self, _cx: &mut WindowContext) -> Arc { + fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc { "Select a command...".into() } - fn update_matches(&mut self, query: String, cx: &mut ViewContext>) -> Task<()> { + fn update_matches( + &mut self, + query: String, + window: &mut Window, + cx: &mut Context>, + ) -> Task<()> { let all_commands = self.all_commands.clone(); - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { let filtered_commands = cx .background_executor() .spawn(async move { @@ -104,9 +109,9 @@ impl PickerDelegate for SlashCommandDelegate { }) .await; - this.update(&mut cx, |this, cx| { + this.update_in(&mut cx, |this, window, cx| { this.delegate.filtered_commands = filtered_commands; - this.delegate.set_selected_index(0, cx); + this.delegate.set_selected_index(0, window, cx); cx.notify(); }) .ok(); @@ -139,25 +144,25 @@ impl PickerDelegate for SlashCommandDelegate { ret } - fn confirm(&mut self, _secondary: bool, cx: &mut ViewContext>) { + fn confirm(&mut self, _secondary: bool, window: &mut Window, cx: &mut Context>) { if let Some(command) = self.filtered_commands.get(self.selected_index) { match command { SlashCommandEntry::Info(info) => { self.active_context_editor .update(cx, |context_editor, cx| { - context_editor.insert_command(&info.name, cx) + context_editor.insert_command(&info.name, window, cx) }) .ok(); } SlashCommandEntry::Advert { on_confirm, .. } => { - on_confirm(cx); + on_confirm(window, cx); } } cx.emit(DismissEvent); } } - fn dismissed(&mut self, _cx: &mut ViewContext>) {} + fn dismissed(&mut self, _window: &mut Window, _cx: &mut Context>) {} fn editor_position(&self) -> PickerEditorPosition { PickerEditorPosition::End @@ -167,7 +172,8 @@ impl PickerDelegate for SlashCommandDelegate { &self, ix: usize, selected: bool, - cx: &mut ViewContext>, + window: &mut Window, + cx: &mut Context>, ) -> Option { let command_info = self.filtered_commands.get(ix)?; @@ -179,7 +185,7 @@ impl PickerDelegate for SlashCommandDelegate { .toggle_state(selected) .tooltip({ let description = info.description.clone(); - move |cx| cx.new_view(|_| Tooltip::new(description.clone())).into() + move |_, cx| cx.new(|_| Tooltip::new(description.clone())).into() }) .child( v_flex() @@ -229,14 +235,14 @@ impl PickerDelegate for SlashCommandDelegate { .inset(true) .spacing(ListItemSpacing::Dense) .toggle_state(selected) - .child(renderer(cx)), + .child(renderer(window, cx)), ), } } } impl RenderOnce for SlashCommandSelector { - fn render(self, cx: &mut WindowContext) -> impl IntoElement { + fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement { let all_models = self .working_set .featured_command_names(cx) @@ -259,7 +265,7 @@ impl RenderOnce for SlashCommandSelector { }) .chain([SlashCommandEntry::Advert { name: "create-your-command".into(), - renderer: |cx| { + renderer: |_, cx| { v_flex() .w_full() .child( @@ -293,7 +299,7 @@ impl RenderOnce for SlashCommandSelector { ) .into_any_element() }, - on_confirm: |cx| cx.open_url("https://zed.dev/docs/extensions/slash-commands"), + on_confirm: |_, cx| cx.open_url("https://zed.dev/docs/extensions/slash-commands"), }]) .collect::>(); @@ -304,8 +310,9 @@ impl RenderOnce for SlashCommandSelector { selected_index: 0, }; - let picker_view = cx.new_view(|cx| { - let picker = Picker::uniform_list(delegate, cx).max_height(Some(rems(20.).into())); + let picker_view = cx.new(|cx| { + let picker = + Picker::uniform_list(delegate, window, cx).max_height(Some(rems(20.).into())); picker }); @@ -314,7 +321,7 @@ impl RenderOnce for SlashCommandSelector { .update(cx, |this, _| this.slash_menu_handle.clone()) .ok(); PopoverMenu::new("model-switcher") - .menu(move |_cx| Some(picker_view.clone())) + .menu(move |_window, _cx| Some(picker_view.clone())) .trigger(self.trigger) .attach(gpui::Corner::TopLeft) .anchor(gpui::Corner::BottomLeft) diff --git a/crates/assistant_settings/src/assistant_settings.rs b/crates/assistant_settings/src/assistant_settings.rs index c98182b24d..12be65b90f 100644 --- a/crates/assistant_settings/src/assistant_settings.rs +++ b/crates/assistant_settings/src/assistant_settings.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use ::open_ai::Model as OpenAiModel; use anthropic::Model as AnthropicModel; use feature_flags::FeatureFlagAppExt; -use gpui::{AppContext, Pixels}; +use gpui::{App, Pixels}; use language_model::{CloudModel, LanguageModel}; use lmstudio::Model as LmStudioModel; use ollama::Model as OllamaModel; @@ -62,7 +62,7 @@ pub struct AssistantSettings { } impl AssistantSettings { - pub fn are_live_diffs_enabled(&self, cx: &AppContext) -> bool { + pub fn are_live_diffs_enabled(&self, cx: &App) -> bool { cx.is_staff() || self.enable_experimental_live_diffs } } @@ -422,7 +422,7 @@ impl Settings for AssistantSettings { fn load( sources: SettingsSources, - _: &mut gpui::AppContext, + _: &mut gpui::App, ) -> anyhow::Result { let mut settings = AssistantSettings::default(); diff --git a/crates/assistant_slash_command/src/assistant_slash_command.rs b/crates/assistant_slash_command/src/assistant_slash_command.rs index d23647684f..f3811dfa8c 100644 --- a/crates/assistant_slash_command/src/assistant_slash_command.rs +++ b/crates/assistant_slash_command/src/assistant_slash_command.rs @@ -8,7 +8,7 @@ pub use crate::slash_command_working_set::*; use anyhow::Result; use futures::stream::{self, BoxStream}; use futures::StreamExt; -use gpui::{AppContext, SharedString, Task, WeakView, WindowContext}; +use gpui::{App, SharedString, Task, WeakEntity, Window}; use language::{BufferSnapshot, CodeLabel, LspAdapterDelegate, OffsetRangeExt}; pub use language_model::Role; use serde::{Deserialize, Serialize}; @@ -18,7 +18,7 @@ use std::{ }; use workspace::{ui::IconName, Workspace}; -pub fn init(cx: &mut AppContext) { +pub fn init(cx: &mut App) { SlashCommandRegistry::default_global(cx); extension_slash_command::init(cx); } @@ -71,7 +71,7 @@ pub trait SlashCommand: 'static + Send + Sync { fn icon(&self) -> IconName { IconName::Slash } - fn label(&self, _cx: &AppContext) -> CodeLabel { + fn label(&self, _cx: &App) -> CodeLabel { CodeLabel::plain(self.name(), None) } fn description(&self) -> String; @@ -80,26 +80,29 @@ pub trait SlashCommand: 'static + Send + Sync { self: Arc, arguments: &[String], cancel: Arc, - workspace: Option>, - cx: &mut WindowContext, + workspace: Option>, + window: &mut Window, + cx: &mut App, ) -> Task>>; fn requires_argument(&self) -> bool; fn accepts_arguments(&self) -> bool { self.requires_argument() } + #[allow(clippy::too_many_arguments)] fn run( self: Arc, arguments: &[String], context_slash_command_output_sections: &[SlashCommandOutputSection], context_buffer: BufferSnapshot, - workspace: WeakView, + workspace: WeakEntity, // TODO: We're just using the `LspAdapterDelegate` here because that is // what the extension API is already expecting. // // It may be that `LspAdapterDelegate` needs a more general name, or // perhaps another kind of delegate is needed here. delegate: Option>, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Task; } diff --git a/crates/assistant_slash_command/src/extension_slash_command.rs b/crates/assistant_slash_command/src/extension_slash_command.rs index 2279f93b1c..1718a750e4 100644 --- a/crates/assistant_slash_command/src/extension_slash_command.rs +++ b/crates/assistant_slash_command/src/extension_slash_command.rs @@ -4,7 +4,7 @@ use std::sync::{atomic::AtomicBool, Arc}; use anyhow::Result; use async_trait::async_trait; use extension::{Extension, ExtensionHostProxy, ExtensionSlashCommandProxy, WorktreeDelegate}; -use gpui::{AppContext, Task, WeakView, WindowContext}; +use gpui::{App, Task, WeakEntity, Window}; use language::{BufferSnapshot, LspAdapterDelegate}; use ui::prelude::*; use workspace::Workspace; @@ -14,7 +14,7 @@ use crate::{ SlashCommandRegistry, SlashCommandResult, }; -pub fn init(cx: &mut AppContext) { +pub fn init(cx: &mut App) { let proxy = ExtensionHostProxy::default_global(cx); proxy.register_slash_command_proxy(SlashCommandRegistryProxy { slash_command_registry: SlashCommandRegistry::global(cx), @@ -97,8 +97,9 @@ impl SlashCommand for ExtensionSlashCommand { self: Arc, arguments: &[String], _cancel: Arc, - _workspace: Option>, - cx: &mut WindowContext, + _workspace: Option>, + _window: &mut Window, + cx: &mut App, ) -> Task>> { let command = self.command.clone(); let arguments = arguments.to_owned(); @@ -127,9 +128,10 @@ impl SlashCommand for ExtensionSlashCommand { arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: BufferSnapshot, - _workspace: WeakView, + _workspace: WeakEntity, delegate: Option>, - cx: &mut WindowContext, + _window: &mut Window, + cx: &mut App, ) -> Task { let command = self.command.clone(); let arguments = arguments.to_owned(); diff --git a/crates/assistant_slash_command/src/slash_command_registry.rs b/crates/assistant_slash_command/src/slash_command_registry.rs index d8a4014cfc..258869840b 100644 --- a/crates/assistant_slash_command/src/slash_command_registry.rs +++ b/crates/assistant_slash_command/src/slash_command_registry.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use collections::{BTreeSet, HashMap}; use derive_more::{Deref, DerefMut}; use gpui::Global; -use gpui::{AppContext, ReadGlobal}; +use gpui::{App, ReadGlobal}; use parking_lot::RwLock; use crate::SlashCommand; @@ -26,14 +26,14 @@ pub struct SlashCommandRegistry { impl SlashCommandRegistry { /// Returns the global [`SlashCommandRegistry`]. - pub fn global(cx: &AppContext) -> Arc { + pub fn global(cx: &App) -> Arc { GlobalSlashCommandRegistry::global(cx).0.clone() } /// Returns the global [`SlashCommandRegistry`]. /// /// Inserts a default [`SlashCommandRegistry`] if one does not yet exist. - pub fn default_global(cx: &mut AppContext) -> Arc { + pub fn default_global(cx: &mut App) -> Arc { cx.default_global::().0.clone() } diff --git a/crates/assistant_slash_command/src/slash_command_working_set.rs b/crates/assistant_slash_command/src/slash_command_working_set.rs index 83f090a4e5..b920e1d217 100644 --- a/crates/assistant_slash_command/src/slash_command_working_set.rs +++ b/crates/assistant_slash_command/src/slash_command_working_set.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use collections::HashMap; -use gpui::AppContext; +use gpui::App; use parking_lot::Mutex; use crate::{SlashCommand, SlashCommandRegistry}; @@ -23,7 +23,7 @@ struct WorkingSetState { } impl SlashCommandWorkingSet { - pub fn command(&self, name: &str, cx: &AppContext) -> Option> { + pub fn command(&self, name: &str, cx: &App) -> Option> { self.state .lock() .context_server_commands_by_name @@ -32,7 +32,7 @@ impl SlashCommandWorkingSet { .or_else(|| SlashCommandRegistry::global(cx).command(name)) } - pub fn command_names(&self, cx: &AppContext) -> Vec> { + pub fn command_names(&self, cx: &App) -> Vec> { let mut command_names = SlashCommandRegistry::global(cx).command_names(); command_names.extend( self.state @@ -45,7 +45,7 @@ impl SlashCommandWorkingSet { command_names } - pub fn featured_command_names(&self, cx: &AppContext) -> Vec> { + pub fn featured_command_names(&self, cx: &App) -> Vec> { SlashCommandRegistry::global(cx).featured_command_names() } diff --git a/crates/assistant_slash_commands/src/assistant_slash_commands.rs b/crates/assistant_slash_commands/src/assistant_slash_commands.rs index 8e124412b6..ea1ae5ab5a 100644 --- a/crates/assistant_slash_commands/src/assistant_slash_commands.rs +++ b/crates/assistant_slash_commands/src/assistant_slash_commands.rs @@ -17,7 +17,7 @@ mod symbols_command; mod tab_command; mod terminal_command; -use gpui::AppContext; +use gpui::App; use language::{CodeLabel, HighlightId}; use ui::ActiveTheme as _; @@ -40,11 +40,7 @@ pub use crate::symbols_command::*; pub use crate::tab_command::*; pub use crate::terminal_command::*; -pub fn create_label_for_command( - command_name: &str, - arguments: &[&str], - cx: &AppContext, -) -> CodeLabel { +pub fn create_label_for_command(command_name: &str, arguments: &[&str], cx: &App) -> CodeLabel { let mut label = CodeLabel::default(); label.push_str(command_name, None); label.push_str(" ", None); diff --git a/crates/assistant_slash_commands/src/auto_command.rs b/crates/assistant_slash_commands/src/auto_command.rs index 40b627609d..a6222ba822 100644 --- a/crates/assistant_slash_commands/src/auto_command.rs +++ b/crates/assistant_slash_commands/src/auto_command.rs @@ -5,7 +5,7 @@ use assistant_slash_command::{ }; use feature_flags::FeatureFlag; use futures::StreamExt; -use gpui::{AppContext, AsyncAppContext, AsyncWindowContext, Task, WeakView, WindowContext}; +use gpui::{App, AsyncAppContext, Task, WeakEntity, Window}; use language::{CodeLabel, LspAdapterDelegate}; use language_model::{ LanguageModelCompletionEvent, LanguageModelRegistry, LanguageModelRequest, @@ -45,7 +45,7 @@ impl SlashCommand for AutoCommand { self.description() } - fn label(&self, cx: &AppContext) -> CodeLabel { + fn label(&self, cx: &App) -> CodeLabel { create_label_for_command("auto", &["--prompt"], cx) } @@ -53,8 +53,9 @@ impl SlashCommand for AutoCommand { self: Arc, _arguments: &[String], _cancel: Arc, - workspace: Option>, - cx: &mut WindowContext, + workspace: Option>, + _window: &mut Window, + cx: &mut App, ) -> Task>> { // There's no autocomplete for a prompt, since it's arbitrary text. // However, we can use this opportunity to kick off a drain of the backlog. @@ -74,7 +75,7 @@ impl SlashCommand for AutoCommand { return Task::ready(Err(anyhow!("No project indexer, cannot use /auto"))); }; - let cx: &mut AppContext = cx; + let cx: &mut App = cx; cx.spawn(|cx: gpui::AsyncAppContext| async move { let task = project_index.read_with(&cx, |project_index, cx| { @@ -96,9 +97,10 @@ impl SlashCommand for AutoCommand { arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: language::BufferSnapshot, - workspace: WeakView, + workspace: WeakEntity, _delegate: Option>, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Task { let Some(workspace) = workspace.upgrade() else { return Task::ready(Err(anyhow::anyhow!("workspace was dropped"))); @@ -115,7 +117,7 @@ impl SlashCommand for AutoCommand { return Task::ready(Err(anyhow!("no project indexer"))); }; - let task = cx.spawn(|cx: AsyncWindowContext| async move { + let task = window.spawn(cx, |cx| async move { let summaries = project_index .read_with(&cx, |project_index, cx| project_index.all_summaries(cx))? .await?; diff --git a/crates/assistant_slash_commands/src/cargo_workspace_command.rs b/crates/assistant_slash_commands/src/cargo_workspace_command.rs index eed3b60761..157c2063ed 100644 --- a/crates/assistant_slash_commands/src/cargo_workspace_command.rs +++ b/crates/assistant_slash_commands/src/cargo_workspace_command.rs @@ -1,10 +1,10 @@ -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, Context as _, Result}; use assistant_slash_command::{ ArgumentCompletion, SlashCommand, SlashCommandOutput, SlashCommandOutputSection, SlashCommandResult, }; use fs::Fs; -use gpui::{AppContext, Model, Task, WeakView}; +use gpui::{App, Entity, Task, WeakEntity}; use language::{BufferSnapshot, LspAdapterDelegate}; use project::{Project, ProjectPath}; use std::{ @@ -76,7 +76,7 @@ impl CargoWorkspaceSlashCommand { Ok(message) } - fn path_to_cargo_toml(project: Model, cx: &mut AppContext) -> Option> { + fn path_to_cargo_toml(project: Entity, cx: &mut App) -> Option> { let worktree = project.read(cx).worktrees(cx).next()?; let worktree = worktree.read(cx); let entry = worktree.entry_for_path("Cargo.toml")?; @@ -107,8 +107,9 @@ impl SlashCommand for CargoWorkspaceSlashCommand { self: Arc, _arguments: &[String], _cancel: Arc, - _workspace: Option>, - _cx: &mut WindowContext, + _workspace: Option>, + _window: &mut Window, + _cx: &mut App, ) -> Task>> { Task::ready(Err(anyhow!("this command does not require argument"))) } @@ -122,9 +123,10 @@ impl SlashCommand for CargoWorkspaceSlashCommand { _arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: BufferSnapshot, - workspace: WeakView, + workspace: WeakEntity, _delegate: Option>, - cx: &mut WindowContext, + _window: &mut Window, + cx: &mut App, ) -> Task { let output = workspace.update(cx, |workspace, cx| { let project = workspace.project().clone(); diff --git a/crates/assistant_slash_commands/src/context_server_command.rs b/crates/assistant_slash_commands/src/context_server_command.rs index f9baf7e675..42f814791d 100644 --- a/crates/assistant_slash_commands/src/context_server_command.rs +++ b/crates/assistant_slash_commands/src/context_server_command.rs @@ -8,7 +8,7 @@ use context_server::{ manager::{ContextServer, ContextServerManager}, types::Prompt, }; -use gpui::{AppContext, Model, Task, WeakView, WindowContext}; +use gpui::{App, Entity, Task, WeakEntity, Window}; use language::{BufferSnapshot, CodeLabel, LspAdapterDelegate}; use std::sync::atomic::AtomicBool; use std::sync::Arc; @@ -19,14 +19,14 @@ use workspace::Workspace; use crate::create_label_for_command; pub struct ContextServerSlashCommand { - server_manager: Model, + server_manager: Entity, server_id: Arc, prompt: Prompt, } impl ContextServerSlashCommand { pub fn new( - server_manager: Model, + server_manager: Entity, server: &Arc, prompt: Prompt, ) -> Self { @@ -43,7 +43,7 @@ impl SlashCommand for ContextServerSlashCommand { self.prompt.name.clone() } - fn label(&self, cx: &AppContext) -> language::CodeLabel { + fn label(&self, cx: &App) -> language::CodeLabel { let mut parts = vec![self.prompt.name.as_str()]; if let Some(args) = &self.prompt.arguments { if let Some(arg) = args.first() { @@ -77,8 +77,9 @@ impl SlashCommand for ContextServerSlashCommand { self: Arc, arguments: &[String], _cancel: Arc, - _workspace: Option>, - cx: &mut WindowContext, + _workspace: Option>, + _window: &mut Window, + cx: &mut App, ) -> Task>> { let Ok((arg_name, arg_value)) = completion_argument(&self.prompt, arguments) else { return Task::ready(Err(anyhow!("Failed to complete argument"))); @@ -128,9 +129,10 @@ impl SlashCommand for ContextServerSlashCommand { arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: BufferSnapshot, - _workspace: WeakView, + _workspace: WeakEntity, _delegate: Option>, - cx: &mut WindowContext, + _window: &mut Window, + cx: &mut App, ) -> Task { let server_id = self.server_id.clone(); let prompt_name = self.prompt.name.clone(); diff --git a/crates/assistant_slash_commands/src/default_command.rs b/crates/assistant_slash_commands/src/default_command.rs index 6fac51143a..6881f89a9e 100644 --- a/crates/assistant_slash_commands/src/default_command.rs +++ b/crates/assistant_slash_commands/src/default_command.rs @@ -3,7 +3,7 @@ use assistant_slash_command::{ ArgumentCompletion, SlashCommand, SlashCommandOutput, SlashCommandOutputSection, SlashCommandResult, }; -use gpui::{Task, WeakView}; +use gpui::{Task, WeakEntity}; use language::{BufferSnapshot, LspAdapterDelegate}; use prompt_library::PromptStore; use std::{ @@ -36,8 +36,9 @@ impl SlashCommand for DefaultSlashCommand { self: Arc, _arguments: &[String], _cancellation_flag: Arc, - _workspace: Option>, - _cx: &mut WindowContext, + _workspace: Option>, + _window: &mut Window, + _cx: &mut App, ) -> Task>> { Task::ready(Err(anyhow!("this command does not require argument"))) } @@ -47,9 +48,10 @@ impl SlashCommand for DefaultSlashCommand { _arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: BufferSnapshot, - _workspace: WeakView, + _workspace: WeakEntity, _delegate: Option>, - cx: &mut WindowContext, + _window: &mut Window, + cx: &mut App, ) -> Task { let store = PromptStore::global(cx); cx.background_executor().spawn(async move { diff --git a/crates/assistant_slash_commands/src/delta_command.rs b/crates/assistant_slash_commands/src/delta_command.rs index ba6c4dde39..0cbd508d19 100644 --- a/crates/assistant_slash_commands/src/delta_command.rs +++ b/crates/assistant_slash_commands/src/delta_command.rs @@ -6,7 +6,7 @@ use assistant_slash_command::{ }; use collections::HashSet; use futures::future; -use gpui::{Task, WeakView, WindowContext}; +use gpui::{App, Task, WeakEntity, Window}; use language::{BufferSnapshot, LspAdapterDelegate}; use std::sync::{atomic::AtomicBool, Arc}; use text::OffsetRangeExt; @@ -40,8 +40,9 @@ impl SlashCommand for DeltaSlashCommand { self: Arc, _arguments: &[String], _cancellation_flag: Arc, - _workspace: Option>, - _cx: &mut WindowContext, + _workspace: Option>, + _window: &mut Window, + _cx: &mut App, ) -> Task>> { Task::ready(Err(anyhow!("this command does not require argument"))) } @@ -51,9 +52,10 @@ impl SlashCommand for DeltaSlashCommand { _arguments: &[String], context_slash_command_output_sections: &[SlashCommandOutputSection], context_buffer: BufferSnapshot, - workspace: WeakView, + workspace: WeakEntity, delegate: Option>, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Task { let mut paths = HashSet::default(); let mut file_command_old_outputs = Vec::new(); @@ -77,6 +79,7 @@ impl SlashCommand for DeltaSlashCommand { context_buffer.clone(), workspace.clone(), delegate.clone(), + window, cx, )); } diff --git a/crates/assistant_slash_commands/src/diagnostics_command.rs b/crates/assistant_slash_commands/src/diagnostics_command.rs index e73d58c7a7..e3a13d4013 100644 --- a/crates/assistant_slash_commands/src/diagnostics_command.rs +++ b/crates/assistant_slash_commands/src/diagnostics_command.rs @@ -4,7 +4,7 @@ use assistant_slash_command::{ SlashCommandResult, }; use fuzzy::{PathMatch, StringMatchCandidate}; -use gpui::{AppContext, Model, Task, View, WeakView}; +use gpui::{App, Entity, Task, WeakEntity}; use language::{ Anchor, BufferSnapshot, DiagnosticEntry, DiagnosticSeverity, LspAdapterDelegate, OffsetRangeExt, ToOffset, @@ -30,8 +30,8 @@ impl DiagnosticsSlashCommand { &self, query: String, cancellation_flag: Arc, - workspace: &View, - cx: &mut AppContext, + workspace: &Entity, + cx: &mut App, ) -> Task> { if query.is_empty() { let workspace = workspace.read(cx); @@ -90,7 +90,7 @@ impl SlashCommand for DiagnosticsSlashCommand { "diagnostics".into() } - fn label(&self, cx: &AppContext) -> language::CodeLabel { + fn label(&self, cx: &App) -> language::CodeLabel { create_label_for_command("diagnostics", &[INCLUDE_WARNINGS_ARGUMENT], cx) } @@ -118,8 +118,9 @@ impl SlashCommand for DiagnosticsSlashCommand { self: Arc, arguments: &[String], cancellation_flag: Arc, - workspace: Option>, - cx: &mut WindowContext, + workspace: Option>, + _: &mut Window, + cx: &mut App, ) -> Task>> { let Some(workspace) = workspace.and_then(|workspace| workspace.upgrade()) else { return Task::ready(Err(anyhow!("workspace was dropped"))); @@ -172,9 +173,10 @@ impl SlashCommand for DiagnosticsSlashCommand { arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: BufferSnapshot, - workspace: WeakView, + workspace: WeakEntity, _delegate: Option>, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Task { let Some(workspace) = workspace.upgrade() else { return Task::ready(Err(anyhow!("workspace was dropped"))); @@ -184,7 +186,7 @@ impl SlashCommand for DiagnosticsSlashCommand { let task = collect_diagnostics(workspace.read(cx).project().clone(), options, cx); - cx.spawn(move |_| async move { + window.spawn(cx, move |_| async move { task.await? .map(|output| output.to_event_stream()) .ok_or_else(|| anyhow!("No diagnostics found")) @@ -223,9 +225,9 @@ impl Options { } fn collect_diagnostics( - project: Model, + project: Entity, options: Options, - cx: &mut AppContext, + cx: &mut App, ) -> Task>> { let error_source = if let Some(path_matcher) = &options.path_matcher { debug_assert_eq!(path_matcher.sources().len(), 1); diff --git a/crates/assistant_slash_commands/src/docs_command.rs b/crates/assistant_slash_commands/src/docs_command.rs index 007abeb909..523534db92 100644 --- a/crates/assistant_slash_commands/src/docs_command.rs +++ b/crates/assistant_slash_commands/src/docs_command.rs @@ -8,7 +8,7 @@ use assistant_slash_command::{ ArgumentCompletion, SlashCommand, SlashCommandOutput, SlashCommandOutputSection, SlashCommandResult, }; -use gpui::{AppContext, BackgroundExecutor, Model, Task, WeakView}; +use gpui::{App, BackgroundExecutor, Entity, Task, WeakEntity}; use indexed_docs::{ DocsDotRsProvider, IndexedDocsRegistry, IndexedDocsStore, LocalRustdocProvider, PackageName, ProviderId, @@ -24,7 +24,7 @@ pub struct DocsSlashCommand; impl DocsSlashCommand { pub const NAME: &'static str = "docs"; - fn path_to_cargo_toml(project: Model, cx: &mut AppContext) -> Option> { + fn path_to_cargo_toml(project: Entity, cx: &mut App) -> Option> { let worktree = project.read(cx).worktrees(cx).next()?; let worktree = worktree.read(cx); let entry = worktree.entry_for_path("Cargo.toml")?; @@ -43,8 +43,8 @@ impl DocsSlashCommand { /// access the workspace so we can read the project. fn ensure_rust_doc_providers_are_registered( &self, - workspace: Option>, - cx: &mut AppContext, + workspace: Option>, + cx: &mut App, ) { let indexed_docs_registry = IndexedDocsRegistry::global(cx); if indexed_docs_registry @@ -164,8 +164,9 @@ impl SlashCommand for DocsSlashCommand { self: Arc, arguments: &[String], _cancel: Arc, - workspace: Option>, - cx: &mut WindowContext, + workspace: Option>, + _: &mut Window, + cx: &mut App, ) -> Task>> { self.ensure_rust_doc_providers_are_registered(workspace, cx); @@ -272,9 +273,10 @@ impl SlashCommand for DocsSlashCommand { arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: BufferSnapshot, - _workspace: WeakView, + _workspace: WeakEntity, _delegate: Option>, - cx: &mut WindowContext, + _: &mut Window, + cx: &mut App, ) -> Task { if arguments.is_empty() { return Task::ready(Err(anyhow!("missing an argument"))); diff --git a/crates/assistant_slash_commands/src/fetch_command.rs b/crates/assistant_slash_commands/src/fetch_command.rs index b6b7dd5713..142773891b 100644 --- a/crates/assistant_slash_commands/src/fetch_command.rs +++ b/crates/assistant_slash_commands/src/fetch_command.rs @@ -9,7 +9,7 @@ use assistant_slash_command::{ SlashCommandResult, }; use futures::AsyncReadExt; -use gpui::{Task, WeakView}; +use gpui::{Task, WeakEntity}; use html_to_markdown::{convert_html_to_markdown, markdown, TagHandler}; use http_client::{AsyncBody, HttpClient, HttpClientWithUrl}; use language::{BufferSnapshot, LspAdapterDelegate}; @@ -124,8 +124,9 @@ impl SlashCommand for FetchSlashCommand { self: Arc, _arguments: &[String], _cancel: Arc, - _workspace: Option>, - _cx: &mut WindowContext, + _workspace: Option>, + _window: &mut Window, + _cx: &mut App, ) -> Task>> { Task::ready(Ok(Vec::new())) } @@ -135,9 +136,10 @@ impl SlashCommand for FetchSlashCommand { arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: BufferSnapshot, - workspace: WeakView, + workspace: WeakEntity, _delegate: Option>, - cx: &mut WindowContext, + _: &mut Window, + cx: &mut App, ) -> Task { let Some(argument) = arguments.first() else { return Task::ready(Err(anyhow!("missing URL"))); diff --git a/crates/assistant_slash_commands/src/file_command.rs b/crates/assistant_slash_commands/src/file_command.rs index ce2355afcb..10d1d88ae9 100644 --- a/crates/assistant_slash_commands/src/file_command.rs +++ b/crates/assistant_slash_commands/src/file_command.rs @@ -6,7 +6,7 @@ use assistant_slash_command::{ use futures::channel::mpsc; use futures::Stream; use fuzzy::PathMatch; -use gpui::{AppContext, Model, Task, View, WeakView}; +use gpui::{App, Entity, Task, WeakEntity}; use language::{BufferSnapshot, CodeLabel, HighlightId, LineEnding, LspAdapterDelegate}; use project::{PathMatchCandidateSet, Project}; use serde::{Deserialize, Serialize}; @@ -28,8 +28,8 @@ impl FileSlashCommand { &self, query: String, cancellation_flag: Arc, - workspace: &View, - cx: &mut AppContext, + workspace: &Entity, + cx: &mut App, ) -> Task> { if query.is_empty() { let workspace = workspace.read(cx); @@ -134,8 +134,9 @@ impl SlashCommand for FileSlashCommand { self: Arc, arguments: &[String], cancellation_flag: Arc, - workspace: Option>, - cx: &mut WindowContext, + workspace: Option>, + _: &mut Window, + cx: &mut App, ) -> Task>> { let Some(workspace) = workspace.and_then(|workspace| workspace.upgrade()) else { return Task::ready(Err(anyhow!("workspace was dropped"))); @@ -187,9 +188,10 @@ impl SlashCommand for FileSlashCommand { arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: BufferSnapshot, - workspace: WeakView, + workspace: WeakEntity, _delegate: Option>, - cx: &mut WindowContext, + _: &mut Window, + cx: &mut App, ) -> Task { let Some(workspace) = workspace.upgrade() else { return Task::ready(Err(anyhow!("workspace was dropped"))); @@ -209,9 +211,9 @@ impl SlashCommand for FileSlashCommand { } fn collect_files( - project: Model, + project: Entity, glob_inputs: &[String], - cx: &mut AppContext, + cx: &mut App, ) -> impl Stream> { let Ok(matchers) = glob_inputs .into_iter() diff --git a/crates/assistant_slash_commands/src/now_command.rs b/crates/assistant_slash_commands/src/now_command.rs index 2db21a72ac..6d4ae75dd7 100644 --- a/crates/assistant_slash_commands/src/now_command.rs +++ b/crates/assistant_slash_commands/src/now_command.rs @@ -7,7 +7,7 @@ use assistant_slash_command::{ SlashCommandResult, }; use chrono::Local; -use gpui::{Task, WeakView}; +use gpui::{Task, WeakEntity}; use language::{BufferSnapshot, LspAdapterDelegate}; use ui::prelude::*; use workspace::Workspace; @@ -35,8 +35,9 @@ impl SlashCommand for NowSlashCommand { self: Arc, _arguments: &[String], _cancel: Arc, - _workspace: Option>, - _cx: &mut WindowContext, + _workspace: Option>, + _window: &mut Window, + _cx: &mut App, ) -> Task>> { Task::ready(Ok(Vec::new())) } @@ -46,9 +47,10 @@ impl SlashCommand for NowSlashCommand { _arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: BufferSnapshot, - _workspace: WeakView, + _workspace: WeakEntity, _delegate: Option>, - _cx: &mut WindowContext, + _window: &mut Window, + _cx: &mut App, ) -> Task { let now = Local::now(); let text = format!("Today is {now}.", now = now.to_rfc2822()); diff --git a/crates/assistant_slash_commands/src/project_command.rs b/crates/assistant_slash_commands/src/project_command.rs index bcef7e2c08..a15dc86e28 100644 --- a/crates/assistant_slash_commands/src/project_command.rs +++ b/crates/assistant_slash_commands/src/project_command.rs @@ -10,7 +10,7 @@ use assistant_slash_command::{ SlashCommandResult, }; use feature_flags::FeatureFlag; -use gpui::{AppContext, Task, WeakView, WindowContext}; +use gpui::{App, Task, WeakEntity}; use language::{Anchor, CodeLabel, LspAdapterDelegate}; use language_model::{LanguageModelRegistry, LanguageModelTool}; use prompt_library::PromptBuilder; @@ -43,7 +43,7 @@ impl SlashCommand for ProjectSlashCommand { "project".into() } - fn label(&self, cx: &AppContext) -> CodeLabel { + fn label(&self, cx: &App) -> CodeLabel { create_label_for_command("project", &[], cx) } @@ -67,8 +67,9 @@ impl SlashCommand for ProjectSlashCommand { self: Arc, _arguments: &[String], _cancel: Arc, - _workspace: Option>, - _cx: &mut WindowContext, + _workspace: Option>, + _window: &mut Window, + _cx: &mut App, ) -> Task>> { Task::ready(Ok(Vec::new())) } @@ -78,9 +79,10 @@ impl SlashCommand for ProjectSlashCommand { _arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], context_buffer: language::BufferSnapshot, - workspace: WeakView, + workspace: WeakEntity, _delegate: Option>, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Task { let model_registry = LanguageModelRegistry::read_global(cx); let current_model = model_registry.active_model(); @@ -97,7 +99,7 @@ impl SlashCommand for ProjectSlashCommand { return Task::ready(Err(anyhow::anyhow!("no project indexer"))); }; - cx.spawn(|mut cx| async move { + window.spawn(cx, |mut cx| async move { let current_model = current_model.ok_or_else(|| anyhow!("no model selected"))?; let prompt = diff --git a/crates/assistant_slash_commands/src/prompt_command.rs b/crates/assistant_slash_commands/src/prompt_command.rs index ed926e3e5d..930a7fb732 100644 --- a/crates/assistant_slash_commands/src/prompt_command.rs +++ b/crates/assistant_slash_commands/src/prompt_command.rs @@ -1,9 +1,9 @@ -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, Context as _, Result}; use assistant_slash_command::{ ArgumentCompletion, SlashCommand, SlashCommandOutput, SlashCommandOutputSection, SlashCommandResult, }; -use gpui::{Task, WeakView}; +use gpui::{Task, WeakEntity}; use language::{BufferSnapshot, LspAdapterDelegate}; use prompt_library::PromptStore; use std::sync::{atomic::AtomicBool, Arc}; @@ -37,8 +37,9 @@ impl SlashCommand for PromptSlashCommand { self: Arc, arguments: &[String], _cancellation_flag: Arc, - _workspace: Option>, - cx: &mut WindowContext, + _workspace: Option>, + _: &mut Window, + cx: &mut App, ) -> Task>> { let store = PromptStore::global(cx); let query = arguments.to_owned().join(" "); @@ -64,9 +65,10 @@ impl SlashCommand for PromptSlashCommand { arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: BufferSnapshot, - _workspace: WeakView, + _workspace: WeakEntity, _delegate: Option>, - cx: &mut WindowContext, + _: &mut Window, + cx: &mut App, ) -> Task { let title = arguments.to_owned().join(" "); if title.trim().is_empty() { diff --git a/crates/assistant_slash_commands/src/search_command.rs b/crates/assistant_slash_commands/src/search_command.rs index 90204ab024..6b75d57de0 100644 --- a/crates/assistant_slash_commands/src/search_command.rs +++ b/crates/assistant_slash_commands/src/search_command.rs @@ -4,7 +4,7 @@ use assistant_slash_command::{ SlashCommandResult, }; use feature_flags::FeatureFlag; -use gpui::{AppContext, Task, WeakView}; +use gpui::{App, Task, WeakEntity}; use language::{CodeLabel, LspAdapterDelegate}; use semantic_index::{LoadedSearchResult, SemanticDb}; use std::{ @@ -34,7 +34,7 @@ impl SlashCommand for SearchSlashCommand { "search".into() } - fn label(&self, cx: &AppContext) -> CodeLabel { + fn label(&self, cx: &App) -> CodeLabel { create_label_for_command("search", &["--n"], cx) } @@ -58,8 +58,9 @@ impl SlashCommand for SearchSlashCommand { self: Arc, _arguments: &[String], _cancel: Arc, - _workspace: Option>, - _cx: &mut WindowContext, + _workspace: Option>, + _window: &mut Window, + _cx: &mut App, ) -> Task>> { Task::ready(Ok(Vec::new())) } @@ -69,9 +70,10 @@ impl SlashCommand for SearchSlashCommand { arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: language::BufferSnapshot, - workspace: WeakView, + workspace: WeakEntity, _delegate: Option>, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Task { let Some(workspace) = workspace.upgrade() else { return Task::ready(Err(anyhow::anyhow!("workspace was dropped"))); @@ -107,7 +109,7 @@ impl SlashCommand for SearchSlashCommand { return Task::ready(Err(anyhow::anyhow!("no project indexer"))); }; - cx.spawn(|cx| async move { + window.spawn(cx, |cx| async move { let results = project_index .read_with(&cx, |project_index, cx| { project_index.search(vec![query.clone()], limit.unwrap_or(5), cx) diff --git a/crates/assistant_slash_commands/src/selection_command.rs b/crates/assistant_slash_commands/src/selection_command.rs index 29af653e8e..fbe4d42bcb 100644 --- a/crates/assistant_slash_commands/src/selection_command.rs +++ b/crates/assistant_slash_commands/src/selection_command.rs @@ -5,8 +5,7 @@ use assistant_slash_command::{ }; use editor::Editor; use futures::StreamExt; -use gpui::{AppContext, Task, WeakView}; -use gpui::{SharedString, ViewContext, WindowContext}; +use gpui::{App, Context, SharedString, Task, WeakEntity, Window}; use language::{BufferSnapshot, CodeLabel, LspAdapterDelegate}; use std::sync::atomic::AtomicBool; use std::sync::Arc; @@ -22,7 +21,7 @@ impl SlashCommand for SelectionCommand { "selection".into() } - fn label(&self, _cx: &AppContext) -> CodeLabel { + fn label(&self, _cx: &App) -> CodeLabel { CodeLabel::plain(self.name(), None) } @@ -50,8 +49,9 @@ impl SlashCommand for SelectionCommand { self: Arc, _arguments: &[String], _cancel: Arc, - _workspace: Option>, - _cx: &mut WindowContext, + _workspace: Option>, + _window: &mut Window, + _cx: &mut App, ) -> Task>> { Task::ready(Err(anyhow!("this command does not require argument"))) } @@ -61,9 +61,10 @@ impl SlashCommand for SelectionCommand { _arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: BufferSnapshot, - workspace: WeakView, + workspace: WeakEntity, _delegate: Option>, - cx: &mut WindowContext, + _window: &mut Window, + cx: &mut App, ) -> Task { let mut events = vec![]; @@ -102,7 +103,7 @@ impl SlashCommand for SelectionCommand { pub fn selections_creases( workspace: &mut workspace::Workspace, - cx: &mut ViewContext, + cx: &mut Context, ) -> Option> { let editor = workspace .active_item(cx) diff --git a/crates/assistant_slash_commands/src/streaming_example_command.rs b/crates/assistant_slash_commands/src/streaming_example_command.rs index 663d9078fa..ed7797843a 100644 --- a/crates/assistant_slash_commands/src/streaming_example_command.rs +++ b/crates/assistant_slash_commands/src/streaming_example_command.rs @@ -9,7 +9,7 @@ use assistant_slash_command::{ }; use feature_flags::FeatureFlag; use futures::channel::mpsc; -use gpui::{Task, WeakView}; +use gpui::{Task, WeakEntity}; use language::{BufferSnapshot, LspAdapterDelegate}; use smol::stream::StreamExt; use smol::Timer; @@ -45,8 +45,9 @@ impl SlashCommand for StreamingExampleSlashCommand { self: Arc, _arguments: &[String], _cancel: Arc, - _workspace: Option>, - _cx: &mut WindowContext, + _workspace: Option>, + _window: &mut Window, + _cx: &mut App, ) -> Task>> { Task::ready(Ok(Vec::new())) } @@ -56,9 +57,10 @@ impl SlashCommand for StreamingExampleSlashCommand { _arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: BufferSnapshot, - _workspace: WeakView, + _workspace: WeakEntity, _delegate: Option>, - cx: &mut WindowContext, + _: &mut Window, + cx: &mut App, ) -> Task { let (events_tx, events_rx) = mpsc::unbounded(); cx.background_executor() diff --git a/crates/assistant_slash_commands/src/symbols_command.rs b/crates/assistant_slash_commands/src/symbols_command.rs index e09787a91a..d44d92058d 100644 --- a/crates/assistant_slash_commands/src/symbols_command.rs +++ b/crates/assistant_slash_commands/src/symbols_command.rs @@ -4,11 +4,11 @@ use assistant_slash_command::{ SlashCommandResult, }; use editor::Editor; -use gpui::{Task, WeakView}; +use gpui::{Task, WeakEntity}; use language::{BufferSnapshot, LspAdapterDelegate}; use std::sync::Arc; use std::{path::Path, sync::atomic::AtomicBool}; -use ui::{IconName, WindowContext}; +use ui::{App, IconName, Window}; use workspace::Workspace; pub struct OutlineSlashCommand; @@ -34,8 +34,9 @@ impl SlashCommand for OutlineSlashCommand { self: Arc, _arguments: &[String], _cancel: Arc, - _workspace: Option>, - _cx: &mut WindowContext, + _workspace: Option>, + _window: &mut Window, + _cx: &mut App, ) -> Task>> { Task::ready(Err(anyhow!("this command does not require argument"))) } @@ -49,9 +50,10 @@ impl SlashCommand for OutlineSlashCommand { _arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: BufferSnapshot, - workspace: WeakView, + workspace: WeakEntity, _delegate: Option>, - cx: &mut WindowContext, + _: &mut Window, + cx: &mut App, ) -> Task { let output = workspace.update(cx, |workspace, cx| { let Some(active_item) = workspace.active_item(cx) else { diff --git a/crates/assistant_slash_commands/src/tab_command.rs b/crates/assistant_slash_commands/src/tab_command.rs index a343ce111d..6ff495bdbe 100644 --- a/crates/assistant_slash_commands/src/tab_command.rs +++ b/crates/assistant_slash_commands/src/tab_command.rs @@ -1,4 +1,4 @@ -use anyhow::{Context, Result}; +use anyhow::{Context as _, Result}; use assistant_slash_command::{ ArgumentCompletion, SlashCommand, SlashCommandOutput, SlashCommandOutputSection, SlashCommandResult, @@ -6,13 +6,13 @@ use assistant_slash_command::{ use collections::{HashMap, HashSet}; use editor::Editor; use futures::future::join_all; -use gpui::{Entity, Task, WeakView}; +use gpui::{Task, WeakEntity}; use language::{BufferSnapshot, CodeLabel, HighlightId, LspAdapterDelegate}; use std::{ path::PathBuf, sync::{atomic::AtomicBool, Arc}, }; -use ui::{prelude::*, ActiveTheme, WindowContext}; +use ui::{prelude::*, ActiveTheme, App, Window}; use util::ResultExt; use workspace::Workspace; @@ -51,8 +51,9 @@ impl SlashCommand for TabSlashCommand { self: Arc, arguments: &[String], cancel: Arc, - workspace: Option>, - cx: &mut WindowContext, + workspace: Option>, + window: &mut Window, + cx: &mut App, ) -> Task>> { let mut has_all_tabs_completion_item = false; let argument_set = arguments @@ -82,10 +83,10 @@ impl SlashCommand for TabSlashCommand { }); let current_query = arguments.last().cloned().unwrap_or_default(); let tab_items_search = - tab_items_for_queries(workspace, &[current_query], cancel, false, cx); + tab_items_for_queries(workspace, &[current_query], cancel, false, window, cx); let comment_id = cx.theme().syntax().highlight_id("comment").map(HighlightId); - cx.spawn(|_| async move { + window.spawn(cx, |_| async move { let tab_items = tab_items_search.await?; let run_command = tab_items.len() == 1; let tab_completion_items = tab_items.into_iter().filter_map(|(path, ..)| { @@ -137,15 +138,17 @@ impl SlashCommand for TabSlashCommand { arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: BufferSnapshot, - workspace: WeakView, + workspace: WeakEntity, _delegate: Option>, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Task { let tab_items_search = tab_items_for_queries( Some(workspace), arguments, Arc::new(AtomicBool::new(false)), true, + window, cx, ); @@ -160,15 +163,16 @@ impl SlashCommand for TabSlashCommand { } fn tab_items_for_queries( - workspace: Option>, + workspace: Option>, queries: &[String], cancel: Arc, strict_match: bool, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Task, BufferSnapshot, usize)>>> { let empty_query = queries.is_empty() || queries.iter().all(|query| query.trim().is_empty()); let queries = queries.to_owned(); - cx.spawn(|mut cx| async move { + window.spawn(cx, |mut cx| async move { let mut open_buffers = workspace .context("no workspace")? @@ -281,7 +285,7 @@ fn tab_items_for_queries( fn active_item_buffer( workspace: &mut Workspace, - cx: &mut ViewContext, + cx: &mut Context, ) -> anyhow::Result { let active_editor = workspace .active_item(cx) diff --git a/crates/assistant_slash_commands/src/terminal_command.rs b/crates/assistant_slash_commands/src/terminal_command.rs index 5abc93deed..2528c4f663 100644 --- a/crates/assistant_slash_commands/src/terminal_command.rs +++ b/crates/assistant_slash_commands/src/terminal_command.rs @@ -6,7 +6,7 @@ use assistant_slash_command::{ ArgumentCompletion, SlashCommand, SlashCommandOutput, SlashCommandOutputSection, SlashCommandResult, }; -use gpui::{AppContext, Task, View, WeakView}; +use gpui::{App, Entity, Task, WeakEntity}; use language::{BufferSnapshot, CodeLabel, LspAdapterDelegate}; use terminal_view::{terminal_panel::TerminalPanel, TerminalView}; use ui::prelude::*; @@ -25,7 +25,7 @@ impl SlashCommand for TerminalSlashCommand { "terminal".into() } - fn label(&self, cx: &AppContext) -> CodeLabel { + fn label(&self, cx: &App) -> CodeLabel { create_label_for_command("terminal", &[LINE_COUNT_ARG], cx) } @@ -53,8 +53,9 @@ impl SlashCommand for TerminalSlashCommand { self: Arc, _arguments: &[String], _cancel: Arc, - _workspace: Option>, - _cx: &mut WindowContext, + _workspace: Option>, + _window: &mut Window, + _cx: &mut App, ) -> Task>> { Task::ready(Ok(Vec::new())) } @@ -64,9 +65,10 @@ impl SlashCommand for TerminalSlashCommand { arguments: &[String], _context_slash_command_output_sections: &[SlashCommandOutputSection], _context_buffer: BufferSnapshot, - workspace: WeakView, + workspace: WeakEntity, _delegate: Option>, - cx: &mut WindowContext, + _: &mut Window, + cx: &mut App, ) -> Task { let Some(workspace) = workspace.upgrade() else { return Task::ready(Err(anyhow::anyhow!("workspace was dropped"))); @@ -107,9 +109,9 @@ impl SlashCommand for TerminalSlashCommand { } fn resolve_active_terminal( - workspace: &View, - cx: &WindowContext, -) -> Option> { + workspace: &Entity, + cx: &mut App, +) -> Option> { if let Some(terminal_view) = workspace .read(cx) .active_item(cx) diff --git a/crates/assistant_tool/src/assistant_tool.rs b/crates/assistant_tool/src/assistant_tool.rs index c993494495..0b4f30da7d 100644 --- a/crates/assistant_tool/src/assistant_tool.rs +++ b/crates/assistant_tool/src/assistant_tool.rs @@ -4,13 +4,13 @@ mod tool_working_set; use std::sync::Arc; use anyhow::Result; -use gpui::{AppContext, Task, WeakView, WindowContext}; +use gpui::{App, Task, WeakEntity, Window}; use workspace::Workspace; pub use crate::tool_registry::*; pub use crate::tool_working_set::*; -pub fn init(cx: &mut AppContext) { +pub fn init(cx: &mut App) { ToolRegistry::default_global(cx); } @@ -31,7 +31,8 @@ pub trait Tool: 'static + Send + Sync { fn run( self: Arc, input: serde_json::Value, - workspace: WeakView, - cx: &mut WindowContext, + workspace: WeakEntity, + window: &mut Window, + cx: &mut App, ) -> Task>; } diff --git a/crates/assistant_tool/src/tool_registry.rs b/crates/assistant_tool/src/tool_registry.rs index d225b6a9a3..26b4821a6d 100644 --- a/crates/assistant_tool/src/tool_registry.rs +++ b/crates/assistant_tool/src/tool_registry.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use collections::HashMap; use derive_more::{Deref, DerefMut}; use gpui::Global; -use gpui::{AppContext, ReadGlobal}; +use gpui::{App, ReadGlobal}; use parking_lot::RwLock; use crate::Tool; @@ -25,14 +25,14 @@ pub struct ToolRegistry { impl ToolRegistry { /// Returns the global [`ToolRegistry`]. - pub fn global(cx: &AppContext) -> Arc { + pub fn global(cx: &App) -> Arc { GlobalToolRegistry::global(cx).0.clone() } /// Returns the global [`ToolRegistry`]. /// /// Inserts a default [`ToolRegistry`] if one does not yet exist. - pub fn default_global(cx: &mut AppContext) -> Arc { + pub fn default_global(cx: &mut App) -> Arc { cx.default_global::().0.clone() } diff --git a/crates/assistant_tool/src/tool_working_set.rs b/crates/assistant_tool/src/tool_working_set.rs index f22f0c7881..bbdb0f87c3 100644 --- a/crates/assistant_tool/src/tool_working_set.rs +++ b/crates/assistant_tool/src/tool_working_set.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use collections::HashMap; -use gpui::AppContext; +use gpui::App; use parking_lot::Mutex; use crate::{Tool, ToolRegistry}; @@ -23,7 +23,7 @@ struct WorkingSetState { } impl ToolWorkingSet { - pub fn tool(&self, name: &str, cx: &AppContext) -> Option> { + pub fn tool(&self, name: &str, cx: &App) -> Option> { self.state .lock() .context_server_tools_by_name @@ -32,7 +32,7 @@ impl ToolWorkingSet { .or_else(|| ToolRegistry::global(cx).tool(name)) } - pub fn tools(&self, cx: &AppContext) -> Vec> { + pub fn tools(&self, cx: &App) -> Vec> { let mut tools = ToolRegistry::global(cx).tools(); tools.extend( self.state diff --git a/crates/assistant_tools/src/assistant_tools.rs b/crates/assistant_tools/src/assistant_tools.rs index 7d145c61b7..b0afd6441f 100644 --- a/crates/assistant_tools/src/assistant_tools.rs +++ b/crates/assistant_tools/src/assistant_tools.rs @@ -1,11 +1,11 @@ mod now_tool; use assistant_tool::ToolRegistry; -use gpui::AppContext; +use gpui::App; use crate::now_tool::NowTool; -pub fn init(cx: &mut AppContext) { +pub fn init(cx: &mut App) { assistant_tool::init(cx); let registry = ToolRegistry::global(cx); diff --git a/crates/assistant_tools/src/now_tool.rs b/crates/assistant_tools/src/now_tool.rs index 707f2be2bd..b9d22b66b4 100644 --- a/crates/assistant_tools/src/now_tool.rs +++ b/crates/assistant_tools/src/now_tool.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use anyhow::{anyhow, Result}; use assistant_tool::Tool; use chrono::{Local, Utc}; -use gpui::{Task, WeakView, WindowContext}; +use gpui::{App, Task, WeakEntity, Window}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -41,8 +41,9 @@ impl Tool for NowTool { fn run( self: Arc, input: serde_json::Value, - _workspace: WeakView, - _cx: &mut WindowContext, + _workspace: WeakEntity, + _window: &mut Window, + _cx: &mut App, ) -> Task> { let input: FileToolInput = match serde_json::from_value(input) { Ok(input) => input, diff --git a/crates/audio/src/assets.rs b/crates/audio/src/assets.rs index 75bcd20cd0..1f5256821e 100644 --- a/crates/audio/src/assets.rs +++ b/crates/audio/src/assets.rs @@ -2,7 +2,7 @@ use std::{io::Cursor, sync::Arc}; use anyhow::Result; use collections::HashMap; -use gpui::{AppContext, AssetSource, Global}; +use gpui::{App, AssetSource, Global}; use rodio::{ source::{Buffered, SamplesConverter}, Decoder, Source, @@ -27,11 +27,11 @@ impl SoundRegistry { }) } - pub fn global(cx: &AppContext) -> Arc { + pub fn global(cx: &App) -> Arc { cx.global::().0.clone() } - pub(crate) fn set_global(source: impl AssetSource, cx: &mut AppContext) { + pub(crate) fn set_global(source: impl AssetSource, cx: &mut App) { cx.set_global(GlobalSoundRegistry(SoundRegistry::new(source))); } diff --git a/crates/audio/src/audio.rs b/crates/audio/src/audio.rs index 118abcc604..55f08c38a1 100644 --- a/crates/audio/src/audio.rs +++ b/crates/audio/src/audio.rs @@ -1,12 +1,12 @@ use assets::SoundRegistry; use derive_more::{Deref, DerefMut}; -use gpui::{AppContext, AssetSource, BorrowAppContext, Global}; +use gpui::{App, AssetSource, BorrowAppContext, Global}; use rodio::{OutputStream, OutputStreamHandle}; use util::ResultExt; mod assets; -pub fn init(source: impl AssetSource, cx: &mut AppContext) { +pub fn init(source: impl AssetSource, cx: &mut App) { SoundRegistry::set_global(source, cx); cx.set_global(GlobalAudio(Audio::new())); } @@ -59,7 +59,7 @@ impl Audio { self.output_handle.as_ref() } - pub fn play_sound(sound: Sound, cx: &mut AppContext) { + pub fn play_sound(sound: Sound, cx: &mut App) { if !cx.has_global::() { return; } @@ -72,7 +72,7 @@ impl Audio { }); } - pub fn end_call(cx: &mut AppContext) { + pub fn end_call(cx: &mut App) { if !cx.has_global::() { return; } diff --git a/crates/auto_update/src/auto_update.rs b/crates/auto_update/src/auto_update.rs index 0f9999b918..e46f79e069 100644 --- a/crates/auto_update/src/auto_update.rs +++ b/crates/auto_update/src/auto_update.rs @@ -1,10 +1,10 @@ -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, Context as _, Result}; use client::{Client, TelemetrySettings}; use db::kvp::KEY_VALUE_STORE; use db::RELEASE_CHANNEL; use gpui::{ - actions, AppContext, AsyncAppContext, Context as _, Global, Model, ModelContext, - SemanticVersion, Task, WindowContext, + actions, App, AppContext as _, AsyncAppContext, Context, Entity, Global, SemanticVersion, Task, + Window, }; use http_client::{AsyncBody, HttpClient, HttpClientWithUrl}; use paths::remote_servers_dir; @@ -112,7 +112,7 @@ impl Settings for AutoUpdateSetting { type FileContent = Option; - fn load(sources: SettingsSources, _: &mut AppContext) -> Result { + fn load(sources: SettingsSources, _: &mut App) -> Result { let auto_update = [sources.server, sources.release_channel, sources.user] .into_iter() .find_map(|value| value.copied().flatten()) @@ -123,24 +123,24 @@ impl Settings for AutoUpdateSetting { } #[derive(Default)] -struct GlobalAutoUpdate(Option>); +struct GlobalAutoUpdate(Option>); impl Global for GlobalAutoUpdate {} -pub fn init(http_client: Arc, cx: &mut AppContext) { +pub fn init(http_client: Arc, cx: &mut App) { AutoUpdateSetting::register(cx); - cx.observe_new_views(|workspace: &mut Workspace, _cx| { - workspace.register_action(|_, action: &Check, cx| check(action, cx)); + cx.observe_new(|workspace: &mut Workspace, _window, _cx| { + workspace.register_action(|_, action: &Check, window, cx| check(action, window, cx)); - workspace.register_action(|_, action, cx| { + workspace.register_action(|_, action, _, cx| { view_release_notes(action, cx); }); }) .detach(); let version = release_channel::AppVersion::global(cx); - let auto_updater = cx.new_model(|cx| { + let auto_updater = cx.new(|cx| { let updater = AutoUpdater::new(version, http_client); let poll_for_updates = ReleaseChannel::try_global(cx) @@ -155,7 +155,7 @@ pub fn init(http_client: Arc, cx: &mut AppContext) { .0 .then(|| updater.start_polling(cx)); - cx.observe_global::(move |updater, cx| { + cx.observe_global::(move |updater: &mut AutoUpdater, cx| { if AutoUpdateSetting::get_global(cx).0 { if update_subscription.is_none() { update_subscription = Some(updater.start_polling(cx)) @@ -172,23 +172,25 @@ pub fn init(http_client: Arc, cx: &mut AppContext) { cx.set_global(GlobalAutoUpdate(Some(auto_updater))); } -pub fn check(_: &Check, cx: &mut WindowContext) { +pub fn check(_: &Check, window: &mut Window, cx: &mut App) { if let Some(message) = option_env!("ZED_UPDATE_EXPLANATION") { - drop(cx.prompt( + drop(window.prompt( gpui::PromptLevel::Info, "Zed was installed via a package manager.", Some(message), &["Ok"], + cx, )); return; } if let Ok(message) = env::var("ZED_UPDATE_EXPLANATION") { - drop(cx.prompt( + drop(window.prompt( gpui::PromptLevel::Info, "Zed was installed via a package manager.", Some(&message), &["Ok"], + cx, )); return; } @@ -203,16 +205,17 @@ pub fn check(_: &Check, cx: &mut WindowContext) { if let Some(updater) = AutoUpdater::get(cx) { updater.update(cx, |updater, cx| updater.poll(cx)); } else { - drop(cx.prompt( + drop(window.prompt( gpui::PromptLevel::Info, "Could not check for updates", Some("Auto-updates disabled for non-bundled app."), &["Ok"], + cx, )); } } -pub fn view_release_notes(_: &ViewReleaseNotes, cx: &mut AppContext) -> Option<()> { +pub fn view_release_notes(_: &ViewReleaseNotes, cx: &mut App) -> Option<()> { let auto_updater = AutoUpdater::get(cx)?; let release_channel = ReleaseChannel::try_global(cx)?; @@ -236,7 +239,7 @@ pub fn view_release_notes(_: &ViewReleaseNotes, cx: &mut AppContext) -> Option<( } impl AutoUpdater { - pub fn get(cx: &mut AppContext) -> Option> { + pub fn get(cx: &mut App) -> Option> { cx.default_global::().0.clone() } @@ -249,7 +252,7 @@ impl AutoUpdater { } } - pub fn start_polling(&self, cx: &mut ModelContext) -> Task> { + pub fn start_polling(&self, cx: &mut Context) -> Task> { cx.spawn(|this, mut cx| async move { loop { this.update(&mut cx, |this, cx| this.poll(cx))?; @@ -258,7 +261,7 @@ impl AutoUpdater { }) } - pub fn poll(&mut self, cx: &mut ModelContext) { + pub fn poll(&mut self, cx: &mut Context) { if self.pending_poll.is_some() || self.status.is_updated() { return; } @@ -287,7 +290,7 @@ impl AutoUpdater { self.status.clone() } - pub fn dismiss_error(&mut self, cx: &mut ModelContext) { + pub fn dismiss_error(&mut self, cx: &mut Context) { self.status = AutoUpdateStatus::Idle; cx.notify(); } @@ -371,7 +374,7 @@ impl AutoUpdater { } async fn get_release( - this: &Model, + this: &Entity, asset: &str, os: &str, arch: &str, @@ -421,7 +424,7 @@ impl AutoUpdater { } async fn get_latest_release( - this: &Model, + this: &Entity, asset: &str, os: &str, arch: &str, @@ -431,7 +434,7 @@ impl AutoUpdater { Self::get_release(this, asset, os, arch, None, release_channel, cx).await } - async fn update(this: Model, mut cx: AsyncAppContext) -> Result<()> { + async fn update(this: Entity, mut cx: AsyncAppContext) -> Result<()> { let (client, current_version, release_channel) = this.update(&mut cx, |this, cx| { this.status = AutoUpdateStatus::Checking; cx.notify(); @@ -509,7 +512,7 @@ impl AutoUpdater { pub fn set_should_show_update_notification( &self, should_show: bool, - cx: &AppContext, + cx: &App, ) -> Task> { cx.background_executor().spawn(async move { if should_show { @@ -528,7 +531,7 @@ impl AutoUpdater { }) } - pub fn should_show_update_notification(&self, cx: &AppContext) -> Task> { + pub fn should_show_update_notification(&self, cx: &App) -> Task> { cx.background_executor().spawn(async move { Ok(KEY_VALUE_STORE .read_kvp(SHOULD_SHOW_UPDATE_NOTIFICATION_KEY)? diff --git a/crates/auto_update_ui/src/auto_update_ui.rs b/crates/auto_update_ui/src/auto_update_ui.rs index 9114375e88..a54ad7ac22 100644 --- a/crates/auto_update_ui/src/auto_update_ui.rs +++ b/crates/auto_update_ui/src/auto_update_ui.rs @@ -2,7 +2,7 @@ mod update_notification; use auto_update::AutoUpdater; use editor::{Editor, MultiBuffer}; -use gpui::{actions, prelude::*, AppContext, SharedString, View, ViewContext}; +use gpui::{actions, prelude::*, App, Context, Entity, SharedString, Window}; use http_client::HttpClient; use markdown_preview::markdown_preview_view::{MarkdownPreviewMode, MarkdownPreviewView}; use release_channel::{AppVersion, ReleaseChannel}; @@ -16,10 +16,10 @@ use crate::update_notification::UpdateNotification; actions!(auto_update, [ViewReleaseNotesLocally]); -pub fn init(cx: &mut AppContext) { - cx.observe_new_views(|workspace: &mut Workspace, _cx| { - workspace.register_action(|workspace, _: &ViewReleaseNotesLocally, cx| { - view_release_notes_locally(workspace, cx); +pub fn init(cx: &mut App) { + cx.observe_new(|workspace: &mut Workspace, _window, _cx| { + workspace.register_action(|workspace, _: &ViewReleaseNotesLocally, window, cx| { + view_release_notes_locally(workspace, window, cx); }); }) .detach(); @@ -31,7 +31,11 @@ struct ReleaseNotesBody { release_notes: String, } -fn view_release_notes_locally(workspace: &mut Workspace, cx: &mut ViewContext) { +fn view_release_notes_locally( + workspace: &mut Workspace, + window: &mut Window, + cx: &mut Context, +) { let release_channel = ReleaseChannel::global(cx); let url = match release_channel { @@ -60,8 +64,8 @@ fn view_release_notes_locally(workspace: &mut Workspace, cx: &mut ViewContext = MarkdownPreviewView::new( - MarkdownPreviewMode::Default, - editor, - workspace_handle, - language_registry, - Some(tab_description), - cx, - ); + let markdown_preview: Entity = + MarkdownPreviewView::new( + MarkdownPreviewMode::Default, + editor, + workspace_handle, + language_registry, + Some(tab_description), + window, + cx, + ); workspace.add_item_to_active_pane( - Box::new(view.clone()), + Box::new(markdown_preview.clone()), None, true, + window, cx, ); cx.notify(); @@ -117,12 +124,12 @@ fn view_release_notes_locally(workspace: &mut Workspace, cx: &mut ViewContext) -> Option<()> { +pub fn notify_of_any_new_update(window: &mut Window, cx: &mut Context) -> Option<()> { let updater = AutoUpdater::get(cx)?; let version = updater.read(cx).current_version(); let should_show_notification = updater.read(cx).should_show_update_notification(cx); - cx.spawn(|workspace, mut cx| async move { + cx.spawn_in(window, |workspace, mut cx| async move { let should_show_notification = should_show_notification.await?; if should_show_notification { workspace.update(&mut cx, |workspace, cx| { @@ -130,7 +137,7 @@ pub fn notify_of_any_new_update(cx: &mut ViewContext) -> Option<()> { workspace.show_notification( NotificationId::unique::(), cx, - |cx| cx.new_view(|_| UpdateNotification::new(version, workspace_handle)), + |cx| cx.new(|_| UpdateNotification::new(version, workspace_handle)), ); updater.update(cx, |updater, cx| { updater diff --git a/crates/auto_update_ui/src/update_notification.rs b/crates/auto_update_ui/src/update_notification.rs index 33ac333a30..e99e26983a 100644 --- a/crates/auto_update_ui/src/update_notification.rs +++ b/crates/auto_update_ui/src/update_notification.rs @@ -1,6 +1,6 @@ use gpui::{ - div, DismissEvent, EventEmitter, InteractiveElement, IntoElement, ParentElement, Render, - SemanticVersion, StatefulInteractiveElement, Styled, ViewContext, WeakView, + div, Context, DismissEvent, EventEmitter, InteractiveElement, IntoElement, ParentElement, + Render, SemanticVersion, StatefulInteractiveElement, Styled, WeakEntity, Window, }; use menu::Cancel; use release_channel::ReleaseChannel; @@ -12,13 +12,13 @@ use workspace::{ pub struct UpdateNotification { version: SemanticVersion, - workspace: WeakView, + workspace: WeakEntity, } impl EventEmitter for UpdateNotification {} impl Render for UpdateNotification { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { let app_name = ReleaseChannel::global(cx).display_name(); v_flex() @@ -37,7 +37,9 @@ impl Render for UpdateNotification { .id("cancel") .child(Icon::new(IconName::Close)) .cursor_pointer() - .on_click(cx.listener(|this, _, cx| this.dismiss(&menu::Cancel, cx))), + .on_click(cx.listener(|this, _, window, cx| { + this.dismiss(&menu::Cancel, window, cx) + })), ), ) .child( @@ -45,24 +47,24 @@ impl Render for UpdateNotification { .id("notes") .child(Label::new("View the release notes")) .cursor_pointer() - .on_click(cx.listener(|this, _, cx| { + .on_click(cx.listener(|this, _, window, cx| { this.workspace .update(cx, |workspace, cx| { - crate::view_release_notes_locally(workspace, cx); + crate::view_release_notes_locally(workspace, window, cx); }) .log_err(); - this.dismiss(&menu::Cancel, cx) + this.dismiss(&menu::Cancel, window, cx) })), ) } } impl UpdateNotification { - pub fn new(version: SemanticVersion, workspace: WeakView) -> Self { + pub fn new(version: SemanticVersion, workspace: WeakEntity) -> Self { Self { version, workspace } } - pub fn dismiss(&mut self, _: &Cancel, cx: &mut ViewContext) { + pub fn dismiss(&mut self, _: &Cancel, _: &mut Window, cx: &mut Context) { cx.emit(DismissEvent); } } diff --git a/crates/breadcrumbs/src/breadcrumbs.rs b/crates/breadcrumbs/src/breadcrumbs.rs index da048d55de..fc9e6d96cd 100644 --- a/crates/breadcrumbs/src/breadcrumbs.rs +++ b/crates/breadcrumbs/src/breadcrumbs.rs @@ -1,7 +1,7 @@ use editor::Editor; use gpui::{ - Element, EventEmitter, FocusableView, IntoElement, ParentElement, Render, StyledText, - Subscription, ViewContext, + Context, Element, EventEmitter, Focusable, IntoElement, ParentElement, Render, StyledText, + Subscription, Window, }; use itertools::Itertools; use std::cmp; @@ -37,7 +37,7 @@ impl Breadcrumbs { impl EventEmitter for Breadcrumbs {} impl Render for Breadcrumbs { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { const MAX_SEGMENTS: usize = 12; let element = h_flex() @@ -72,7 +72,7 @@ impl Render for Breadcrumbs { } let highlighted_segments = segments.into_iter().map(|segment| { - let mut text_style = cx.text_style(); + let mut text_style = window.text_style(); if let Some(font) = segment.font { text_style.font_family = font.family; text_style.font_features = font.features; @@ -101,28 +101,30 @@ impl Render for Breadcrumbs { .style(ButtonStyle::Transparent) .on_click({ let editor = editor.clone(); - move |_, cx| { + move |_, window, cx| { if let Some((editor, callback)) = editor .upgrade() .zip(zed_actions::outline::TOGGLE_OUTLINE.get()) { - callback(editor.to_any(), cx); + callback(editor.to_any(), window, cx); } } }) - .tooltip(move |cx| { + .tooltip(move |window, cx| { if let Some(editor) = editor.upgrade() { let focus_handle = editor.read(cx).focus_handle(cx); Tooltip::for_action_in( "Show Symbol Outline", &zed_actions::outline::ToggleOutline, &focus_handle, + window, cx, ) } else { Tooltip::for_action( "Show Symbol Outline", &zed_actions::outline::ToggleOutline, + window, cx, ) } @@ -140,7 +142,8 @@ impl ToolbarItemView for Breadcrumbs { fn set_active_pane_item( &mut self, active_pane_item: Option<&dyn ItemHandle>, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> ToolbarItemLocation { cx.notify(); self.active_item = None; @@ -149,10 +152,11 @@ impl ToolbarItemView for Breadcrumbs { return ToolbarItemLocation::Hidden; }; - let this = cx.view().downgrade(); + let this = cx.model().downgrade(); self.subscription = Some(item.subscribe_to_item_events( + window, cx, - Box::new(move |event, cx| { + Box::new(move |event, _, cx| { if let ItemEvent::UpdateBreadcrumbs = event { this.update(cx, |this, cx| { cx.notify(); @@ -170,7 +174,12 @@ impl ToolbarItemView for Breadcrumbs { item.breadcrumb_location(cx) } - fn pane_focus_update(&mut self, pane_focused: bool, _: &mut ViewContext) { + fn pane_focus_update( + &mut self, + pane_focused: bool, + _window: &mut Window, + _: &mut Context, + ) { self.pane_focused = pane_focused; } } diff --git a/crates/call/src/call_settings.rs b/crates/call/src/call_settings.rs index 21b2279a8f..e15fd38067 100644 --- a/crates/call/src/call_settings.rs +++ b/crates/call/src/call_settings.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use gpui::AppContext; +use gpui::App; use schemars::JsonSchema; use serde_derive::{Deserialize, Serialize}; use settings::{Settings, SettingsSources}; @@ -29,7 +29,7 @@ impl Settings for CallSettings { type FileContent = CallSettingsContent; - fn load(sources: SettingsSources, _: &mut AppContext) -> Result { + fn load(sources: SettingsSources, _: &mut App) -> Result { sources.json_merge() } } diff --git a/crates/call/src/cross_platform/mod.rs b/crates/call/src/cross_platform/mod.rs index 7530c0b265..950a07d86b 100644 --- a/crates/call/src/cross_platform/mod.rs +++ b/crates/call/src/cross_platform/mod.rs @@ -8,8 +8,8 @@ use client::{proto, ChannelId, Client, TypedEnvelope, User, UserStore, ZED_ALWAY use collections::HashSet; use futures::{channel::oneshot, future::Shared, Future, FutureExt}; use gpui::{ - AppContext, AsyncAppContext, Context, EventEmitter, Global, Model, ModelContext, Subscription, - Task, WeakModel, + App, AppContext as _, AsyncAppContext, Context, Entity, EventEmitter, Global, Subscription, + Task, WeakEntity, }; use postage::watch; use project::Project; @@ -23,18 +23,18 @@ pub use livekit_client::{ pub use participant::ParticipantLocation; pub use room::Room; -struct GlobalActiveCall(Model); +struct GlobalActiveCall(Entity); impl Global for GlobalActiveCall {} -pub fn init(client: Arc, user_store: Model, cx: &mut AppContext) { +pub fn init(client: Arc, user_store: Entity, cx: &mut App) { livekit_client::init( cx.background_executor().dispatcher.clone(), cx.http_client(), ); CallSettings::register(cx); - let active_call = cx.new_model(|cx| ActiveCall::new(client, user_store, cx)); + let active_call = cx.new(|cx| ActiveCall::new(client, user_store, cx)); cx.set_global(GlobalActiveCall(active_call)); } @@ -46,7 +46,7 @@ impl OneAtATime { /// spawn a task in the given context. /// if another task is spawned before that resolves, or if the OneAtATime itself is dropped, the first task will be cancelled and return Ok(None) /// otherwise you'll see the result of the task. - fn spawn(&mut self, cx: &mut AppContext, f: F) -> Task>> + fn spawn(&mut self, cx: &mut App, f: F) -> Task>> where F: 'static + FnOnce(AsyncAppContext) -> Fut, Fut: Future>, @@ -79,9 +79,9 @@ pub struct IncomingCall { /// Singleton global maintaining the user's participation in a room across workspaces. pub struct ActiveCall { - room: Option<(Model, Vec)>, - pending_room_creation: Option, Arc>>>>, - location: Option>, + room: Option<(Entity, Vec)>, + pending_room_creation: Option, Arc>>>>, + location: Option>, _join_debouncer: OneAtATime, pending_invites: HashSet, incoming_call: ( @@ -89,14 +89,14 @@ pub struct ActiveCall { watch::Receiver>, ), client: Arc, - user_store: Model, + user_store: Entity, _subscriptions: Vec, } impl EventEmitter for ActiveCall {} impl ActiveCall { - fn new(client: Arc, user_store: Model, cx: &mut ModelContext) -> Self { + fn new(client: Arc, user_store: Entity, cx: &mut Context) -> Self { Self { room: None, pending_room_creation: None, @@ -113,12 +113,12 @@ impl ActiveCall { } } - pub fn channel_id(&self, cx: &AppContext) -> Option { + pub fn channel_id(&self, cx: &App) -> Option { self.room()?.read(cx).channel_id() } async fn handle_incoming_call( - this: Model, + this: Entity, envelope: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result { @@ -145,7 +145,7 @@ impl ActiveCall { } async fn handle_call_canceled( - this: Model, + this: Entity, envelope: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result<()> { @@ -161,11 +161,11 @@ impl ActiveCall { Ok(()) } - pub fn global(cx: &AppContext) -> Model { + pub fn global(cx: &App) -> Entity { cx.global::().0.clone() } - pub fn try_global(cx: &AppContext) -> Option> { + pub fn try_global(cx: &App) -> Option> { cx.try_global::() .map(|call| call.0.clone()) } @@ -173,8 +173,8 @@ impl ActiveCall { pub fn invite( &mut self, called_user_id: u64, - initial_project: Option>, - cx: &mut ModelContext, + initial_project: Option>, + cx: &mut Context, ) -> Task> { if !self.pending_invites.insert(called_user_id) { return Task::ready(Err(anyhow!("user was already invited"))); @@ -269,7 +269,7 @@ impl ActiveCall { pub fn cancel_invite( &mut self, called_user_id: u64, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { let room_id = if let Some(room) = self.room() { room.read(cx).id() @@ -293,7 +293,7 @@ impl ActiveCall { self.incoming_call.1.clone() } - pub fn accept_incoming(&mut self, cx: &mut ModelContext) -> Task> { + pub fn accept_incoming(&mut self, cx: &mut Context) -> Task> { if self.room.is_some() { return Task::ready(Err(anyhow!("cannot join while on another call"))); } @@ -326,7 +326,7 @@ impl ActiveCall { }) } - pub fn decline_incoming(&mut self, _: &mut ModelContext) -> Result<()> { + pub fn decline_incoming(&mut self, _: &mut Context) -> Result<()> { let call = self .incoming_call .0 @@ -343,8 +343,8 @@ impl ActiveCall { pub fn join_channel( &mut self, channel_id: ChannelId, - cx: &mut ModelContext, - ) -> Task>>> { + cx: &mut Context, + ) -> Task>>> { if let Some(room) = self.room().cloned() { if room.read(cx).channel_id() == Some(channel_id) { return Task::ready(Ok(Some(room))); @@ -374,7 +374,7 @@ impl ActiveCall { }) } - pub fn hang_up(&mut self, cx: &mut ModelContext) -> Task> { + pub fn hang_up(&mut self, cx: &mut Context) -> Task> { cx.notify(); self.report_call_event("Call Ended", cx); @@ -391,8 +391,8 @@ impl ActiveCall { pub fn share_project( &mut self, - project: Model, - cx: &mut ModelContext, + project: Entity, + cx: &mut Context, ) -> Task> { if let Some((room, _)) = self.room.as_ref() { self.report_call_event("Project Shared", cx); @@ -404,8 +404,8 @@ impl ActiveCall { pub fn unshare_project( &mut self, - project: Model, - cx: &mut ModelContext, + project: Entity, + cx: &mut Context, ) -> Result<()> { if let Some((room, _)) = self.room.as_ref() { self.report_call_event("Project Unshared", cx); @@ -415,14 +415,14 @@ impl ActiveCall { } } - pub fn location(&self) -> Option<&WeakModel> { + pub fn location(&self) -> Option<&WeakEntity> { self.location.as_ref() } pub fn set_location( &mut self, - project: Option<&Model>, - cx: &mut ModelContext, + project: Option<&Entity>, + cx: &mut Context, ) -> Task> { if project.is_some() || !*ZED_ALWAYS_ACTIVE { self.location = project.map(|project| project.downgrade()); @@ -433,11 +433,7 @@ impl ActiveCall { Task::ready(Ok(())) } - fn set_room( - &mut self, - room: Option>, - cx: &mut ModelContext, - ) -> Task> { + fn set_room(&mut self, room: Option>, cx: &mut Context) -> Task> { if room.as_ref() == self.room.as_ref().map(|room| &room.0) { Task::ready(Ok(())) } else { @@ -473,7 +469,7 @@ impl ActiveCall { } } - pub fn room(&self) -> Option<&Model> { + pub fn room(&self) -> Option<&Entity> { self.room.as_ref().map(|(room, _)| room) } @@ -485,7 +481,7 @@ impl ActiveCall { &self.pending_invites } - pub fn report_call_event(&self, operation: &'static str, cx: &mut AppContext) { + pub fn report_call_event(&self, operation: &'static str, cx: &mut App) { if let Some(room) = self.room() { let room = room.read(cx); telemetry::event!( diff --git a/crates/call/src/cross_platform/participant.rs b/crates/call/src/cross_platform/participant.rs index 16e0107158..c512a59375 100644 --- a/crates/call/src/cross_platform/participant.rs +++ b/crates/call/src/cross_platform/participant.rs @@ -1,7 +1,7 @@ use anyhow::{anyhow, Result}; use client::{proto, ParticipantIndex, User}; use collections::HashMap; -use gpui::WeakModel; +use gpui::WeakEntity; use livekit_client::AudioStream; use project::Project; use std::sync::Arc; @@ -36,7 +36,7 @@ impl ParticipantLocation { #[derive(Clone, Default)] pub struct LocalParticipant { pub projects: Vec, - pub active_project: Option>, + pub active_project: Option>, pub role: proto::ChannelRole, } diff --git a/crates/call/src/cross_platform/room.rs b/crates/call/src/cross_platform/room.rs index 7ad274a1dd..82539e8187 100644 --- a/crates/call/src/cross_platform/room.rs +++ b/crates/call/src/cross_platform/room.rs @@ -11,9 +11,7 @@ use client::{ use collections::{BTreeMap, HashMap, HashSet}; use fs::Fs; use futures::{FutureExt, StreamExt}; -use gpui::{ - AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Task, WeakModel, -}; +use gpui::{App, AppContext, AsyncAppContext, Context, Entity, EventEmitter, Task, WeakEntity}; use language::LanguageRegistry; use livekit::{ capture_local_audio_track, capture_local_video_track, @@ -71,8 +69,8 @@ pub struct Room { channel_id: Option, live_kit: Option, status: RoomStatus, - shared_projects: HashSet>, - joined_projects: HashSet>, + shared_projects: HashSet>, + joined_projects: HashSet>, local_participant: LocalParticipant, remote_participants: BTreeMap, pending_participants: Vec>, @@ -80,7 +78,7 @@ pub struct Room { pending_call_count: usize, leave_when_empty: bool, client: Arc, - user_store: Model, + user_store: Entity, follows_by_leader_id_project_id: HashMap<(PeerId, u64), Vec>, client_subscriptions: Vec, _subscriptions: Vec, @@ -115,8 +113,8 @@ impl Room { channel_id: Option, livekit_connection_info: Option, client: Arc, - user_store: Model, - cx: &mut ModelContext, + user_store: Entity, + cx: &mut Context, ) -> Self { spawn_room_connection(livekit_connection_info, cx); @@ -161,15 +159,15 @@ impl Room { pub(crate) fn create( called_user_id: u64, - initial_project: Option>, + initial_project: Option>, client: Arc, - user_store: Model, - cx: &mut AppContext, - ) -> Task>> { + user_store: Entity, + cx: &mut App, + ) -> Task>> { cx.spawn(move |mut cx| async move { let response = client.request(proto::CreateRoom {}).await?; let room_proto = response.room.ok_or_else(|| anyhow!("invalid room"))?; - let room = cx.new_model(|cx| { + let room = cx.new(|cx| { let mut room = Self::new( room_proto.id, None, @@ -211,9 +209,9 @@ impl Room { pub(crate) async fn join_channel( channel_id: ChannelId, client: Arc, - user_store: Model, + user_store: Entity, cx: AsyncAppContext, - ) -> Result> { + ) -> Result> { Self::from_join_response( client .request(proto::JoinChannel { @@ -229,9 +227,9 @@ impl Room { pub(crate) async fn join( room_id: u64, client: Arc, - user_store: Model, + user_store: Entity, cx: AsyncAppContext, - ) -> Result> { + ) -> Result> { Self::from_join_response( client.request(proto::JoinRoom { id: room_id }).await?, client, @@ -240,13 +238,13 @@ impl Room { ) } - fn released(&mut self, cx: &mut AppContext) { + fn released(&mut self, cx: &mut App) { if self.status.is_online() { self.leave_internal(cx).detach_and_log_err(cx); } } - fn app_will_quit(&mut self, cx: &mut ModelContext) -> impl Future { + fn app_will_quit(&mut self, cx: &mut Context) -> impl Future { let task = if self.status.is_online() { let leave = self.leave_internal(cx); Some(cx.background_executor().spawn(async move { @@ -263,18 +261,18 @@ impl Room { } } - pub fn mute_on_join(cx: &AppContext) -> bool { + pub fn mute_on_join(cx: &App) -> bool { CallSettings::get_global(cx).mute_on_join || client::IMPERSONATE_LOGIN.is_some() } fn from_join_response( response: proto::JoinRoomResponse, client: Arc, - user_store: Model, + user_store: Entity, mut cx: AsyncAppContext, - ) -> Result> { + ) -> Result> { let room_proto = response.room.ok_or_else(|| anyhow!("invalid room"))?; - let room = cx.new_model(|cx| { + let room = cx.new(|cx| { Self::new( room_proto.id, response.channel_id.map(ChannelId), @@ -300,12 +298,12 @@ impl Room { && self.pending_call_count == 0 } - pub(crate) fn leave(&mut self, cx: &mut ModelContext) -> Task> { + pub(crate) fn leave(&mut self, cx: &mut Context) -> Task> { cx.notify(); self.leave_internal(cx) } - fn leave_internal(&mut self, cx: &mut AppContext) -> Task> { + fn leave_internal(&mut self, cx: &mut App) -> Task> { if self.status.is_offline() { return Task::ready(Err(anyhow!("room is offline"))); } @@ -322,7 +320,7 @@ impl Room { }) } - pub(crate) fn clear_state(&mut self, cx: &mut AppContext) { + pub(crate) fn clear_state(&mut self, cx: &mut App) { for project in self.shared_projects.drain() { if let Some(project) = project.upgrade() { project.update(cx, |project, cx| { @@ -350,7 +348,7 @@ impl Room { } async fn maintain_connection( - this: WeakModel, + this: WeakEntity, client: Arc, mut cx: AsyncAppContext, ) -> Result<()> { @@ -436,7 +434,7 @@ impl Room { )) } - fn rejoin(&mut self, cx: &mut ModelContext) -> Task> { + fn rejoin(&mut self, cx: &mut Context) -> Task> { let mut projects = HashMap::default(); let mut reshared_projects = Vec::new(); let mut rejoined_projects = Vec::new(); @@ -562,7 +560,7 @@ impl Room { &mut self, user_id: u64, role: proto::ChannelRole, - cx: &ModelContext, + cx: &Context, ) -> Task> { let client = self.client.clone(); let room_id = self.id; @@ -594,7 +592,7 @@ impl Room { } /// Returns the most 'active' projects, defined as most people in the project - pub fn most_active_project(&self, cx: &AppContext) -> Option<(u64, u64)> { + pub fn most_active_project(&self, cx: &App) -> Option<(u64, u64)> { let mut project_hosts_and_guest_counts = HashMap::, u32)>::default(); for participant in self.remote_participants.values() { match participant.location { @@ -631,7 +629,7 @@ impl Room { } async fn handle_room_updated( - this: Model, + this: Entity, envelope: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result<()> { @@ -642,7 +640,7 @@ impl Room { this.update(&mut cx, |this, cx| this.apply_room_update(room, cx))? } - fn apply_room_update(&mut self, room: proto::Room, cx: &mut ModelContext) -> Result<()> { + fn apply_room_update(&mut self, room: proto::Room, cx: &mut Context) -> Result<()> { log::trace!( "client {:?}. room update: {:?}", self.client.user_id(), @@ -666,11 +664,7 @@ impl Room { } } - fn start_room_connection( - &self, - mut room: proto::Room, - cx: &mut ModelContext, - ) -> Task<()> { + fn start_room_connection(&self, mut room: proto::Room, cx: &mut Context) -> Task<()> { // Filter ourselves out from the room's participants. let local_participant_ix = room .participants @@ -916,11 +910,7 @@ impl Room { }) } - fn livekit_room_updated( - &mut self, - event: RoomEvent, - cx: &mut ModelContext, - ) -> Result<()> { + fn livekit_room_updated(&mut self, event: RoomEvent, cx: &mut Context) -> Result<()> { log::trace!( "client {:?}. livekit event: {:?}", self.client.user_id(), @@ -1090,7 +1080,7 @@ impl Room { &mut self, called_user_id: u64, initial_project_id: Option, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { if self.status.is_offline() { return Task::ready(Err(anyhow!("room is offline"))); @@ -1124,8 +1114,8 @@ impl Room { id: u64, language_registry: Arc, fs: Arc, - cx: &mut ModelContext, - ) -> Task>> { + cx: &mut Context, + ) -> Task>> { let client = self.client.clone(); let user_store = self.user_store.clone(); cx.emit(Event::RemoteProjectJoined { project_id: id }); @@ -1149,8 +1139,8 @@ impl Room { pub fn share_project( &mut self, - project: Model, - cx: &mut ModelContext, + project: Entity, + cx: &mut Context, ) -> Task> { if let Some(project_id) = project.read(cx).remote_id() { return Task::ready(Ok(project_id)); @@ -1187,8 +1177,8 @@ impl Room { pub(crate) fn unshare_project( &mut self, - project: Model, - cx: &mut ModelContext, + project: Entity, + cx: &mut Context, ) -> Result<()> { let project_id = match project.read(cx).remote_id() { Some(project_id) => project_id, @@ -1206,8 +1196,8 @@ impl Room { pub(crate) fn set_location( &mut self, - project: Option<&Model>, - cx: &mut ModelContext, + project: Option<&Entity>, + cx: &mut Context, ) -> Task> { if self.status.is_offline() { return Task::ready(Err(anyhow!("room is offline"))); @@ -1299,7 +1289,7 @@ impl Room { } #[track_caller] - pub fn share_microphone(&mut self, cx: &mut ModelContext) -> Task> { + pub fn share_microphone(&mut self, cx: &mut Context) -> Task> { if self.status.is_offline() { return Task::ready(Err(anyhow!("room is offline"))); } @@ -1375,7 +1365,7 @@ impl Room { }) } - pub fn share_screen(&mut self, cx: &mut ModelContext) -> Task> { + pub fn share_screen(&mut self, cx: &mut Context) -> Task> { if self.status.is_offline() { return Task::ready(Err(anyhow!("room is offline"))); } @@ -1460,7 +1450,7 @@ impl Room { }) } - pub fn toggle_mute(&mut self, cx: &mut ModelContext) { + pub fn toggle_mute(&mut self, cx: &mut Context) { if let Some(live_kit) = self.live_kit.as_mut() { // When unmuting, undeafen if the user was deafened before. let was_deafened = live_kit.deafened; @@ -1486,7 +1476,7 @@ impl Room { } } - pub fn toggle_deafen(&mut self, cx: &mut ModelContext) { + pub fn toggle_deafen(&mut self, cx: &mut Context) { if let Some(live_kit) = self.live_kit.as_mut() { // When deafening, mute the microphone if it was not already muted. // When un-deafening, unmute the microphone, unless it was explicitly muted. @@ -1504,7 +1494,7 @@ impl Room { } } - pub fn unshare_screen(&mut self, cx: &mut ModelContext) -> Result<()> { + pub fn unshare_screen(&mut self, cx: &mut Context) -> Result<()> { if self.status.is_offline() { return Err(anyhow!("room is offline")); } @@ -1535,7 +1525,7 @@ impl Room { } } - fn set_deafened(&mut self, deafened: bool, cx: &mut ModelContext) -> Option<()> { + fn set_deafened(&mut self, deafened: bool, cx: &mut Context) -> Option<()> { let live_kit = self.live_kit.as_mut()?; cx.notify(); for (_, participant) in live_kit.room.remote_participants() { @@ -1549,11 +1539,7 @@ impl Room { None } - fn set_mute( - &mut self, - should_mute: bool, - cx: &mut ModelContext, - ) -> Option>> { + fn set_mute(&mut self, should_mute: bool, cx: &mut Context) -> Option>> { let live_kit = self.live_kit.as_mut()?; cx.notify(); @@ -1589,7 +1575,7 @@ impl Room { fn spawn_room_connection( livekit_connection_info: Option, - cx: &mut ModelContext<'_, Room>, + cx: &mut Context<'_, Room>, ) { if let Some(connection_info) = livekit_connection_info { cx.spawn(|this, mut cx| async move { @@ -1651,7 +1637,7 @@ struct LiveKitRoom { } impl LiveKitRoom { - fn stop_publishing(&mut self, cx: &mut ModelContext) { + fn stop_publishing(&mut self, cx: &mut Context) { let mut tracks_to_unpublish = Vec::new(); if let LocalTrack::Published { track_publication, .. diff --git a/crates/call/src/macos/mod.rs b/crates/call/src/macos/mod.rs index 5186a6d285..24d05603a5 100644 --- a/crates/call/src/macos/mod.rs +++ b/crates/call/src/macos/mod.rs @@ -8,8 +8,8 @@ use client::{proto, ChannelId, Client, TypedEnvelope, User, UserStore, ZED_ALWAY use collections::HashSet; use futures::{channel::oneshot, future::Shared, Future, FutureExt}; use gpui::{ - AppContext, AsyncAppContext, Context, EventEmitter, Global, Model, ModelContext, Subscription, - Task, WeakModel, + App, AppContext as _, AsyncAppContext, Context, Entity, EventEmitter, Global, Subscription, + Task, WeakEntity, }; use postage::watch; use project::Project; @@ -20,14 +20,14 @@ use std::sync::Arc; pub use participant::ParticipantLocation; pub use room::Room; -struct GlobalActiveCall(Model); +struct GlobalActiveCall(Entity); impl Global for GlobalActiveCall {} -pub fn init(client: Arc, user_store: Model, cx: &mut AppContext) { +pub fn init(client: Arc, user_store: Entity, cx: &mut App) { CallSettings::register(cx); - let active_call = cx.new_model(|cx| ActiveCall::new(client, user_store, cx)); + let active_call = cx.new(|cx| ActiveCall::new(client, user_store, cx)); cx.set_global(GlobalActiveCall(active_call)); } @@ -39,7 +39,7 @@ impl OneAtATime { /// spawn a task in the given context. /// if another task is spawned before that resolves, or if the OneAtATime itself is dropped, the first task will be cancelled and return Ok(None) /// otherwise you'll see the result of the task. - fn spawn(&mut self, cx: &mut AppContext, f: F) -> Task>> + fn spawn(&mut self, cx: &mut App, f: F) -> Task>> where F: 'static + FnOnce(AsyncAppContext) -> Fut, Fut: Future>, @@ -72,9 +72,9 @@ pub struct IncomingCall { /// Singleton global maintaining the user's participation in a room across workspaces. pub struct ActiveCall { - room: Option<(Model, Vec)>, - pending_room_creation: Option, Arc>>>>, - location: Option>, + room: Option<(Entity, Vec)>, + pending_room_creation: Option, Arc>>>>, + location: Option>, _join_debouncer: OneAtATime, pending_invites: HashSet, incoming_call: ( @@ -82,14 +82,14 @@ pub struct ActiveCall { watch::Receiver>, ), client: Arc, - user_store: Model, + user_store: Entity, _subscriptions: Vec, } impl EventEmitter for ActiveCall {} impl ActiveCall { - fn new(client: Arc, user_store: Model, cx: &mut ModelContext) -> Self { + fn new(client: Arc, user_store: Entity, cx: &mut Context) -> Self { Self { room: None, pending_room_creation: None, @@ -106,12 +106,12 @@ impl ActiveCall { } } - pub fn channel_id(&self, cx: &AppContext) -> Option { + pub fn channel_id(&self, cx: &App) -> Option { self.room()?.read(cx).channel_id() } async fn handle_incoming_call( - this: Model, + this: Entity, envelope: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result { @@ -138,7 +138,7 @@ impl ActiveCall { } async fn handle_call_canceled( - this: Model, + this: Entity, envelope: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result<()> { @@ -154,11 +154,11 @@ impl ActiveCall { Ok(()) } - pub fn global(cx: &AppContext) -> Model { + pub fn global(cx: &App) -> Entity { cx.global::().0.clone() } - pub fn try_global(cx: &AppContext) -> Option> { + pub fn try_global(cx: &App) -> Option> { cx.try_global::() .map(|call| call.0.clone()) } @@ -166,8 +166,8 @@ impl ActiveCall { pub fn invite( &mut self, called_user_id: u64, - initial_project: Option>, - cx: &mut ModelContext, + initial_project: Option>, + cx: &mut Context, ) -> Task> { if !self.pending_invites.insert(called_user_id) { return Task::ready(Err(anyhow!("user was already invited"))); @@ -262,7 +262,7 @@ impl ActiveCall { pub fn cancel_invite( &mut self, called_user_id: u64, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { let room_id = if let Some(room) = self.room() { room.read(cx).id() @@ -286,7 +286,7 @@ impl ActiveCall { self.incoming_call.1.clone() } - pub fn accept_incoming(&mut self, cx: &mut ModelContext) -> Task> { + pub fn accept_incoming(&mut self, cx: &mut Context) -> Task> { if self.room.is_some() { return Task::ready(Err(anyhow!("cannot join while on another call"))); } @@ -319,7 +319,7 @@ impl ActiveCall { }) } - pub fn decline_incoming(&mut self, _: &mut ModelContext) -> Result<()> { + pub fn decline_incoming(&mut self, _: &mut Context) -> Result<()> { let call = self .incoming_call .0 @@ -336,8 +336,8 @@ impl ActiveCall { pub fn join_channel( &mut self, channel_id: ChannelId, - cx: &mut ModelContext, - ) -> Task>>> { + cx: &mut Context, + ) -> Task>>> { if let Some(room) = self.room().cloned() { if room.read(cx).channel_id() == Some(channel_id) { return Task::ready(Ok(Some(room))); @@ -367,7 +367,7 @@ impl ActiveCall { }) } - pub fn hang_up(&mut self, cx: &mut ModelContext) -> Task> { + pub fn hang_up(&mut self, cx: &mut Context) -> Task> { cx.notify(); self.report_call_event("Call Ended", cx); @@ -384,8 +384,8 @@ impl ActiveCall { pub fn share_project( &mut self, - project: Model, - cx: &mut ModelContext, + project: Entity, + cx: &mut Context, ) -> Task> { if let Some((room, _)) = self.room.as_ref() { self.report_call_event("Project Shared", cx); @@ -397,8 +397,8 @@ impl ActiveCall { pub fn unshare_project( &mut self, - project: Model, - cx: &mut ModelContext, + project: Entity, + cx: &mut Context, ) -> Result<()> { if let Some((room, _)) = self.room.as_ref() { self.report_call_event("Project Unshared", cx); @@ -408,14 +408,14 @@ impl ActiveCall { } } - pub fn location(&self) -> Option<&WeakModel> { + pub fn location(&self) -> Option<&WeakEntity> { self.location.as_ref() } pub fn set_location( &mut self, - project: Option<&Model>, - cx: &mut ModelContext, + project: Option<&Entity>, + cx: &mut Context, ) -> Task> { if project.is_some() || !*ZED_ALWAYS_ACTIVE { self.location = project.map(|project| project.downgrade()); @@ -426,11 +426,7 @@ impl ActiveCall { Task::ready(Ok(())) } - fn set_room( - &mut self, - room: Option>, - cx: &mut ModelContext, - ) -> Task> { + fn set_room(&mut self, room: Option>, cx: &mut Context) -> Task> { if room.as_ref() == self.room.as_ref().map(|room| &room.0) { Task::ready(Ok(())) } else { @@ -466,7 +462,7 @@ impl ActiveCall { } } - pub fn room(&self) -> Option<&Model> { + pub fn room(&self) -> Option<&Entity> { self.room.as_ref().map(|(room, _)| room) } @@ -478,7 +474,7 @@ impl ActiveCall { &self.pending_invites } - pub fn report_call_event(&self, operation: &'static str, cx: &mut AppContext) { + pub fn report_call_event(&self, operation: &'static str, cx: &mut App) { if let Some(room) = self.room() { let room = room.read(cx); telemetry::event!( diff --git a/crates/call/src/macos/participant.rs b/crates/call/src/macos/participant.rs index dc7527487f..1f1a63a10e 100644 --- a/crates/call/src/macos/participant.rs +++ b/crates/call/src/macos/participant.rs @@ -2,7 +2,7 @@ use anyhow::{anyhow, Result}; use client::ParticipantIndex; use client::{proto, User}; use collections::HashMap; -use gpui::WeakModel; +use gpui::WeakEntity; pub use livekit_client_macos::Frame; pub use livekit_client_macos::{RemoteAudioTrack, RemoteVideoTrack}; use project::Project; @@ -35,7 +35,7 @@ impl ParticipantLocation { #[derive(Clone, Default)] pub struct LocalParticipant { pub projects: Vec, - pub active_project: Option>, + pub active_project: Option>, pub role: proto::ChannelRole, } diff --git a/crates/call/src/macos/room.rs b/crates/call/src/macos/room.rs index 987c056437..8cb81816b2 100644 --- a/crates/call/src/macos/room.rs +++ b/crates/call/src/macos/room.rs @@ -12,7 +12,7 @@ use collections::{BTreeMap, HashMap, HashSet}; use fs::Fs; use futures::{FutureExt, StreamExt}; use gpui::{ - AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Task, WeakModel, + App, AppContext as _, AsyncAppContext, Context, Entity, EventEmitter, Task, WeakEntity, }; use language::LanguageRegistry; use livekit_client_macos::{LocalAudioTrack, LocalTrackPublication, LocalVideoTrack, RoomUpdate}; @@ -62,8 +62,8 @@ pub struct Room { channel_id: Option, live_kit: Option, status: RoomStatus, - shared_projects: HashSet>, - joined_projects: HashSet>, + shared_projects: HashSet>, + joined_projects: HashSet>, local_participant: LocalParticipant, remote_participants: BTreeMap, pending_participants: Vec>, @@ -71,7 +71,7 @@ pub struct Room { pending_call_count: usize, leave_when_empty: bool, client: Arc, - user_store: Model, + user_store: Entity, follows_by_leader_id_project_id: HashMap<(PeerId, u64), Vec>, client_subscriptions: Vec, _subscriptions: Vec, @@ -109,8 +109,8 @@ impl Room { channel_id: Option, live_kit_connection_info: Option, client: Arc, - user_store: Model, - cx: &mut ModelContext, + user_store: Entity, + cx: &mut Context, ) -> Self { let live_kit_room = if let Some(connection_info) = live_kit_connection_info { let room = livekit_client_macos::Room::new(); @@ -225,15 +225,15 @@ impl Room { pub(crate) fn create( called_user_id: u64, - initial_project: Option>, + initial_project: Option>, client: Arc, - user_store: Model, - cx: &mut AppContext, - ) -> Task>> { + user_store: Entity, + cx: &mut App, + ) -> Task>> { cx.spawn(move |mut cx| async move { let response = client.request(proto::CreateRoom {}).await?; let room_proto = response.room.ok_or_else(|| anyhow!("invalid room"))?; - let room = cx.new_model(|cx| { + let room = cx.new(|cx| { let mut room = Self::new( room_proto.id, None, @@ -275,9 +275,9 @@ impl Room { pub(crate) async fn join_channel( channel_id: ChannelId, client: Arc, - user_store: Model, + user_store: Entity, cx: AsyncAppContext, - ) -> Result> { + ) -> Result> { Self::from_join_response( client .request(proto::JoinChannel { @@ -293,9 +293,9 @@ impl Room { pub(crate) async fn join( room_id: u64, client: Arc, - user_store: Model, + user_store: Entity, cx: AsyncAppContext, - ) -> Result> { + ) -> Result> { Self::from_join_response( client.request(proto::JoinRoom { id: room_id }).await?, client, @@ -304,13 +304,13 @@ impl Room { ) } - fn released(&mut self, cx: &mut AppContext) { + fn released(&mut self, cx: &mut App) { if self.status.is_online() { self.leave_internal(cx).detach_and_log_err(cx); } } - fn app_will_quit(&mut self, cx: &mut ModelContext) -> impl Future { + fn app_will_quit(&mut self, cx: &mut Context) -> impl Future { let task = if self.status.is_online() { let leave = self.leave_internal(cx); Some(cx.background_executor().spawn(async move { @@ -327,18 +327,18 @@ impl Room { } } - pub fn mute_on_join(cx: &AppContext) -> bool { + pub fn mute_on_join(cx: &App) -> bool { CallSettings::get_global(cx).mute_on_join || client::IMPERSONATE_LOGIN.is_some() } fn from_join_response( response: proto::JoinRoomResponse, client: Arc, - user_store: Model, + user_store: Entity, mut cx: AsyncAppContext, - ) -> Result> { + ) -> Result> { let room_proto = response.room.ok_or_else(|| anyhow!("invalid room"))?; - let room = cx.new_model(|cx| { + let room = cx.new(|cx| { Self::new( room_proto.id, response.channel_id.map(ChannelId), @@ -364,12 +364,12 @@ impl Room { && self.pending_call_count == 0 } - pub(crate) fn leave(&mut self, cx: &mut ModelContext) -> Task> { + pub(crate) fn leave(&mut self, cx: &mut Context) -> Task> { cx.notify(); self.leave_internal(cx) } - fn leave_internal(&mut self, cx: &mut AppContext) -> Task> { + fn leave_internal(&mut self, cx: &mut App) -> Task> { if self.status.is_offline() { return Task::ready(Err(anyhow!("room is offline"))); } @@ -386,7 +386,7 @@ impl Room { }) } - pub(crate) fn clear_state(&mut self, cx: &mut AppContext) { + pub(crate) fn clear_state(&mut self, cx: &mut App) { for project in self.shared_projects.drain() { if let Some(project) = project.upgrade() { project.update(cx, |project, cx| { @@ -414,7 +414,7 @@ impl Room { } async fn maintain_connection( - this: WeakModel, + this: WeakEntity, client: Arc, mut cx: AsyncAppContext, ) -> Result<()> { @@ -500,7 +500,7 @@ impl Room { )) } - fn rejoin(&mut self, cx: &mut ModelContext) -> Task> { + fn rejoin(&mut self, cx: &mut Context) -> Task> { let mut projects = HashMap::default(); let mut reshared_projects = Vec::new(); let mut rejoined_projects = Vec::new(); @@ -626,7 +626,7 @@ impl Room { &mut self, user_id: u64, role: proto::ChannelRole, - cx: &ModelContext, + cx: &Context, ) -> Task> { let client = self.client.clone(); let room_id = self.id; @@ -658,7 +658,7 @@ impl Room { } /// Returns the most 'active' projects, defined as most people in the project - pub fn most_active_project(&self, cx: &AppContext) -> Option<(u64, u64)> { + pub fn most_active_project(&self, cx: &App) -> Option<(u64, u64)> { let mut project_hosts_and_guest_counts = HashMap::, u32)>::default(); for participant in self.remote_participants.values() { match participant.location { @@ -695,7 +695,7 @@ impl Room { } async fn handle_room_updated( - this: Model, + this: Entity, envelope: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result<()> { @@ -706,11 +706,7 @@ impl Room { this.update(&mut cx, |this, cx| this.apply_room_update(room, cx))? } - fn apply_room_update( - &mut self, - mut room: proto::Room, - cx: &mut ModelContext, - ) -> Result<()> { + fn apply_room_update(&mut self, mut room: proto::Room, cx: &mut Context) -> Result<()> { // Filter ourselves out from the room's participants. let local_participant_ix = room .participants @@ -976,11 +972,7 @@ impl Room { } } - fn live_kit_room_updated( - &mut self, - update: RoomUpdate, - cx: &mut ModelContext, - ) -> Result<()> { + fn live_kit_room_updated(&mut self, update: RoomUpdate, cx: &mut Context) -> Result<()> { match update { RoomUpdate::SubscribedToRemoteVideoTrack(track) => { let user_id = track.publisher_id().parse()?; @@ -1132,7 +1124,7 @@ impl Room { &mut self, called_user_id: u64, initial_project_id: Option, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { if self.status.is_offline() { return Task::ready(Err(anyhow!("room is offline"))); @@ -1166,8 +1158,8 @@ impl Room { id: u64, language_registry: Arc, fs: Arc, - cx: &mut ModelContext, - ) -> Task>> { + cx: &mut Context, + ) -> Task>> { let client = self.client.clone(); let user_store = self.user_store.clone(); cx.emit(Event::RemoteProjectJoined { project_id: id }); @@ -1191,8 +1183,8 @@ impl Room { pub fn share_project( &mut self, - project: Model, - cx: &mut ModelContext, + project: Entity, + cx: &mut Context, ) -> Task> { if let Some(project_id) = project.read(cx).remote_id() { return Task::ready(Ok(project_id)); @@ -1229,8 +1221,8 @@ impl Room { pub(crate) fn unshare_project( &mut self, - project: Model, - cx: &mut ModelContext, + project: Entity, + cx: &mut Context, ) -> Result<()> { let project_id = match project.read(cx).remote_id() { Some(project_id) => project_id, @@ -1248,8 +1240,8 @@ impl Room { pub(crate) fn set_location( &mut self, - project: Option<&Model>, - cx: &mut ModelContext, + project: Option<&Entity>, + cx: &mut Context, ) -> Task> { if self.status.is_offline() { return Task::ready(Err(anyhow!("room is offline"))); @@ -1340,7 +1332,7 @@ impl Room { } #[track_caller] - pub fn share_microphone(&mut self, cx: &mut ModelContext) -> Task> { + pub fn share_microphone(&mut self, cx: &mut Context) -> Task> { if self.status.is_offline() { return Task::ready(Err(anyhow!("room is offline"))); } @@ -1416,7 +1408,7 @@ impl Room { }) } - pub fn share_screen(&mut self, cx: &mut ModelContext) -> Task> { + pub fn share_screen(&mut self, cx: &mut Context) -> Task> { if self.status.is_offline() { return Task::ready(Err(anyhow!("room is offline"))); } else if self.is_screen_sharing() { @@ -1497,7 +1489,7 @@ impl Room { }) } - pub fn toggle_mute(&mut self, cx: &mut ModelContext) { + pub fn toggle_mute(&mut self, cx: &mut Context) { if let Some(live_kit) = self.live_kit.as_mut() { // When unmuting, undeafen if the user was deafened before. let was_deafened = live_kit.deafened; @@ -1525,7 +1517,7 @@ impl Room { } } - pub fn toggle_deafen(&mut self, cx: &mut ModelContext) { + pub fn toggle_deafen(&mut self, cx: &mut Context) { if let Some(live_kit) = self.live_kit.as_mut() { // When deafening, mute the microphone if it was not already muted. // When un-deafening, unmute the microphone, unless it was explicitly muted. @@ -1545,7 +1537,7 @@ impl Room { } } - pub fn unshare_screen(&mut self, cx: &mut ModelContext) -> Result<()> { + pub fn unshare_screen(&mut self, cx: &mut Context) -> Result<()> { if self.status.is_offline() { return Err(anyhow!("room is offline")); } @@ -1572,11 +1564,7 @@ impl Room { } } - fn set_deafened( - &mut self, - deafened: bool, - cx: &mut ModelContext, - ) -> Option>> { + fn set_deafened(&mut self, deafened: bool, cx: &mut Context) -> Option>> { let live_kit = self.live_kit.as_mut()?; cx.notify(); @@ -1606,11 +1594,7 @@ impl Room { })) } - fn set_mute( - &mut self, - should_mute: bool, - cx: &mut ModelContext, - ) -> Option>> { + fn set_mute(&mut self, should_mute: bool, cx: &mut Context) -> Option>> { let live_kit = self.live_kit.as_mut()?; cx.notify(); @@ -1660,7 +1644,7 @@ struct LiveKitRoom { } impl LiveKitRoom { - fn stop_publishing(&mut self, cx: &mut ModelContext) { + fn stop_publishing(&mut self, cx: &mut Context) { if let LocalTrack::Published { track_publication, .. } = mem::replace(&mut self.microphone_track, LocalTrack::None) diff --git a/crates/channel/src/channel.rs b/crates/channel/src/channel.rs index b9547bef1a..13b66c7dc3 100644 --- a/crates/channel/src/channel.rs +++ b/crates/channel/src/channel.rs @@ -3,7 +3,7 @@ mod channel_chat; mod channel_store; use client::{Client, UserStore}; -use gpui::{AppContext, Model}; +use gpui::{App, Entity}; use std::sync::Arc; pub use channel_buffer::{ChannelBuffer, ChannelBufferEvent, ACKNOWLEDGE_DEBOUNCE_INTERVAL}; @@ -16,7 +16,7 @@ pub use channel_store::{Channel, ChannelEvent, ChannelMembership, ChannelStore}; #[cfg(test)] mod channel_store_tests; -pub fn init(client: &Arc, user_store: Model, cx: &mut AppContext) { +pub fn init(client: &Arc, user_store: Entity, cx: &mut App) { channel_store::init(client, user_store, cx); channel_buffer::init(&client.clone().into()); channel_chat::init(&client.clone().into()); diff --git a/crates/channel/src/channel_buffer.rs b/crates/channel/src/channel_buffer.rs index 0a4a259648..1ef78dcdba 100644 --- a/crates/channel/src/channel_buffer.rs +++ b/crates/channel/src/channel_buffer.rs @@ -2,7 +2,7 @@ use crate::{Channel, ChannelStore}; use anyhow::Result; use client::{ChannelId, Client, Collaborator, UserStore, ZED_ALWAYS_ACTIVE}; use collections::HashMap; -use gpui::{AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Task}; +use gpui::{App, AppContext as _, AsyncAppContext, Context, Entity, EventEmitter, Task}; use language::proto::serialize_version; use rpc::{ proto::{self, PeerId}, @@ -23,9 +23,9 @@ pub struct ChannelBuffer { pub channel_id: ChannelId, connected: bool, collaborators: HashMap, - user_store: Model, - channel_store: Model, - buffer: Model, + user_store: Entity, + channel_store: Entity, + buffer: Entity, buffer_epoch: u64, client: Arc, subscription: Option, @@ -45,10 +45,10 @@ impl ChannelBuffer { pub(crate) async fn new( channel: Arc, client: Arc, - user_store: Model, - channel_store: Model, + user_store: Entity, + channel_store: Entity, mut cx: AsyncAppContext, - ) -> Result> { + ) -> Result> { let response = client .request(proto::JoinChannelBuffer { channel_id: channel.id.0, @@ -62,7 +62,7 @@ impl ChannelBuffer { .map(language::proto::deserialize_operation) .collect::, _>>()?; - let buffer = cx.new_model(|cx| { + let buffer = cx.new(|cx| { let capability = channel_store.read(cx).channel_capability(channel.id); language::Buffer::remote(buffer_id, response.replica_id as u16, capability, base_text) })?; @@ -70,7 +70,7 @@ impl ChannelBuffer { let subscription = client.subscribe_to_entity(channel.id.0)?; - anyhow::Ok(cx.new_model(|cx| { + anyhow::Ok(cx.new(|cx| { cx.subscribe(&buffer, Self::on_buffer_update).detach(); cx.on_release(Self::release).detach(); let mut this = Self { @@ -81,7 +81,7 @@ impl ChannelBuffer { collaborators: Default::default(), acknowledge_task: None, channel_id: channel.id, - subscription: Some(subscription.set_model(&cx.handle(), &mut cx.to_async())), + subscription: Some(subscription.set_model(&cx.model(), &mut cx.to_async())), user_store, channel_store, }; @@ -90,7 +90,7 @@ impl ChannelBuffer { })?) } - fn release(&mut self, _: &mut AppContext) { + fn release(&mut self, _: &mut App) { if self.connected { if let Some(task) = self.acknowledge_task.take() { task.detach(); @@ -103,18 +103,18 @@ impl ChannelBuffer { } } - pub fn remote_id(&self, cx: &AppContext) -> BufferId { + pub fn remote_id(&self, cx: &App) -> BufferId { self.buffer.read(cx).remote_id() } - pub fn user_store(&self) -> &Model { + pub fn user_store(&self) -> &Entity { &self.user_store } pub(crate) fn replace_collaborators( &mut self, collaborators: Vec, - cx: &mut ModelContext, + cx: &mut Context, ) { let mut new_collaborators = HashMap::default(); for collaborator in collaborators { @@ -136,7 +136,7 @@ impl ChannelBuffer { } async fn handle_update_channel_buffer( - this: Model, + this: Entity, update_channel_buffer: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result<()> { @@ -157,7 +157,7 @@ impl ChannelBuffer { } async fn handle_update_channel_buffer_collaborators( - this: Model, + this: Entity, message: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result<()> { @@ -170,9 +170,9 @@ impl ChannelBuffer { fn on_buffer_update( &mut self, - _: Model, + _: Entity, event: &language::BufferEvent, - cx: &mut ModelContext, + cx: &mut Context, ) { match event { language::BufferEvent::Operation { @@ -201,7 +201,7 @@ impl ChannelBuffer { } } - pub fn acknowledge_buffer_version(&mut self, cx: &mut ModelContext<'_, ChannelBuffer>) { + pub fn acknowledge_buffer_version(&mut self, cx: &mut Context<'_, ChannelBuffer>) { let buffer = self.buffer.read(cx); let version = buffer.version(); let buffer_id = buffer.remote_id().into(); @@ -227,7 +227,7 @@ impl ChannelBuffer { self.buffer_epoch } - pub fn buffer(&self) -> Model { + pub fn buffer(&self) -> Entity { self.buffer.clone() } @@ -235,14 +235,14 @@ impl ChannelBuffer { &self.collaborators } - pub fn channel(&self, cx: &AppContext) -> Option> { + pub fn channel(&self, cx: &App) -> Option> { self.channel_store .read(cx) .channel_for_id(self.channel_id) .cloned() } - pub(crate) fn disconnect(&mut self, cx: &mut ModelContext) { + pub(crate) fn disconnect(&mut self, cx: &mut Context) { log::info!("channel buffer {} disconnected", self.channel_id); if self.connected { self.connected = false; @@ -252,7 +252,7 @@ impl ChannelBuffer { } } - pub(crate) fn channel_changed(&mut self, cx: &mut ModelContext) { + pub(crate) fn channel_changed(&mut self, cx: &mut Context) { cx.emit(ChannelBufferEvent::ChannelChanged); cx.notify() } @@ -261,7 +261,7 @@ impl ChannelBuffer { self.connected } - pub fn replica_id(&self, cx: &AppContext) -> u16 { + pub fn replica_id(&self, cx: &App) -> u16 { self.buffer.read(cx).replica_id() } } diff --git a/crates/channel/src/channel_chat.rs b/crates/channel/src/channel_chat.rs index e5b5b74c16..306b1f9426 100644 --- a/crates/channel/src/channel_chat.rs +++ b/crates/channel/src/channel_chat.rs @@ -8,7 +8,7 @@ use client::{ use collections::HashSet; use futures::lock::Mutex; use gpui::{ - AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Task, WeakModel, + App, AppContext as _, AsyncAppContext, Context, Entity, EventEmitter, Task, WeakEntity, }; use rand::prelude::*; use rpc::AnyProtoClient; @@ -24,12 +24,12 @@ pub struct ChannelChat { pub channel_id: ChannelId, messages: SumTree, acknowledged_message_ids: HashSet, - channel_store: Model, + channel_store: Entity, loaded_all_messages: bool, last_acknowledged_id: Option, next_pending_message_id: usize, first_loaded_message_id: Option, - user_store: Model, + user_store: Entity, rpc: Arc, outgoing_messages_lock: Arc>, rng: StdRng, @@ -105,11 +105,11 @@ pub fn init(client: &AnyProtoClient) { impl ChannelChat { pub async fn new( channel: Arc, - channel_store: Model, - user_store: Model, + channel_store: Entity, + user_store: Entity, client: Arc, mut cx: AsyncAppContext, - ) -> Result> { + ) -> Result> { let channel_id = channel.id; let subscription = client.subscribe_to_entity(channel_id.0).unwrap(); @@ -119,7 +119,7 @@ impl ChannelChat { }) .await?; - let handle = cx.new_model(|cx| { + let handle = cx.new(|cx| { cx.on_release(Self::release).detach(); Self { channel_id: channel.id, @@ -134,7 +134,7 @@ impl ChannelChat { last_acknowledged_id: None, rng: StdRng::from_entropy(), first_loaded_message_id: None, - _subscription: subscription.set_model(&cx.handle(), &mut cx.to_async()), + _subscription: subscription.set_model(&cx.model(), &mut cx.to_async()), } })?; Self::handle_loaded_messages( @@ -149,7 +149,7 @@ impl ChannelChat { Ok(handle) } - fn release(&mut self, _: &mut AppContext) { + fn release(&mut self, _: &mut App) { self.rpc .send(proto::LeaveChannelChat { channel_id: self.channel_id.0, @@ -157,7 +157,7 @@ impl ChannelChat { .log_err(); } - pub fn channel(&self, cx: &AppContext) -> Option> { + pub fn channel(&self, cx: &App) -> Option> { self.channel_store .read(cx) .channel_for_id(self.channel_id) @@ -171,7 +171,7 @@ impl ChannelChat { pub fn send_message( &mut self, message: MessageParams, - cx: &mut ModelContext, + cx: &mut Context, ) -> Result>> { if message.text.trim().is_empty() { Err(anyhow!("message body can't be empty"))?; @@ -231,7 +231,7 @@ impl ChannelChat { })) } - pub fn remove_message(&mut self, id: u64, cx: &mut ModelContext) -> Task> { + pub fn remove_message(&mut self, id: u64, cx: &mut Context) -> Task> { let response = self.rpc.request(proto::RemoveChannelMessage { channel_id: self.channel_id.0, message_id: id, @@ -249,7 +249,7 @@ impl ChannelChat { &mut self, id: u64, message: MessageParams, - cx: &mut ModelContext, + cx: &mut Context, ) -> Result>> { self.message_update( ChannelMessageId::Saved(id), @@ -274,7 +274,7 @@ impl ChannelChat { })) } - pub fn load_more_messages(&mut self, cx: &mut ModelContext) -> Option>> { + pub fn load_more_messages(&mut self, cx: &mut Context) -> Option>> { if self.loaded_all_messages { return None; } @@ -323,7 +323,7 @@ impl ChannelChat { /// /// For now, we always maintain a suffix of the channel's messages. pub async fn load_history_since_message( - chat: Model, + chat: Entity, message_id: u64, mut cx: AsyncAppContext, ) -> Option { @@ -357,7 +357,7 @@ impl ChannelChat { } } - pub fn acknowledge_last_message(&mut self, cx: &mut ModelContext) { + pub fn acknowledge_last_message(&mut self, cx: &mut Context) { if let ChannelMessageId::Saved(latest_message_id) = self.messages.summary().max_id { if self .last_acknowledged_id @@ -378,8 +378,8 @@ impl ChannelChat { } async fn handle_loaded_messages( - this: WeakModel, - user_store: Model, + this: WeakEntity, + user_store: Entity, rpc: Arc, proto_messages: Vec, loaded_all_messages: bool, @@ -437,7 +437,7 @@ impl ChannelChat { Ok(()) } - pub fn rejoin(&mut self, cx: &mut ModelContext) { + pub fn rejoin(&mut self, cx: &mut Context) { let user_store = self.user_store.clone(); let rpc = self.rpc.clone(); let channel_id = self.channel_id; @@ -527,7 +527,7 @@ impl ChannelChat { } async fn handle_message_sent( - this: Model, + this: Entity, message: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result<()> { @@ -551,7 +551,7 @@ impl ChannelChat { } async fn handle_message_removed( - this: Model, + this: Entity, message: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result<()> { @@ -562,7 +562,7 @@ impl ChannelChat { } async fn handle_message_updated( - this: Model, + this: Entity, message: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result<()> { @@ -586,7 +586,7 @@ impl ChannelChat { Ok(()) } - fn insert_messages(&mut self, messages: SumTree, cx: &mut ModelContext) { + fn insert_messages(&mut self, messages: SumTree, cx: &mut Context) { if let Some((first_message, last_message)) = messages.first().zip(messages.last()) { let nonces = messages .cursor::<()>(&()) @@ -645,7 +645,7 @@ impl ChannelChat { } } - fn message_removed(&mut self, id: u64, cx: &mut ModelContext) { + fn message_removed(&mut self, id: u64, cx: &mut Context) { let mut cursor = self.messages.cursor::(&()); let mut messages = cursor.slice(&ChannelMessageId::Saved(id), Bias::Left, &()); if let Some(item) = cursor.item() { @@ -683,7 +683,7 @@ impl ChannelChat { body: String, mentions: Vec<(Range, u64)>, edited_at: Option, - cx: &mut ModelContext, + cx: &mut Context, ) { let mut cursor = self.messages.cursor::(&()); let mut messages = cursor.slice(&id, Bias::Left, &()); @@ -712,7 +712,7 @@ impl ChannelChat { async fn messages_from_proto( proto_messages: Vec, - user_store: &Model, + user_store: &Entity, cx: &mut AsyncAppContext, ) -> Result> { let messages = ChannelMessage::from_proto_vec(proto_messages, user_store, cx).await?; @@ -724,7 +724,7 @@ async fn messages_from_proto( impl ChannelMessage { pub async fn from_proto( message: proto::ChannelMessage, - user_store: &Model, + user_store: &Entity, cx: &mut AsyncAppContext, ) -> Result { let sender = user_store @@ -769,7 +769,7 @@ impl ChannelMessage { pub async fn from_proto_vec( proto_messages: Vec, - user_store: &Model, + user_store: &Entity, cx: &mut AsyncAppContext, ) -> Result> { let unique_user_ids = proto_messages diff --git a/crates/channel/src/channel_store.rs b/crates/channel/src/channel_store.rs index d627d8fe15..7a112d0029 100644 --- a/crates/channel/src/channel_store.rs +++ b/crates/channel/src/channel_store.rs @@ -7,8 +7,8 @@ use client::{ChannelId, Client, ClientSettings, Subscription, User, UserId, User use collections::{hash_map, HashMap, HashSet}; use futures::{channel::mpsc, future::Shared, Future, FutureExt, StreamExt}; use gpui::{ - AppContext, AsyncAppContext, Context, EventEmitter, Global, Model, ModelContext, SharedString, - Task, WeakModel, + App, AppContext as _, AsyncAppContext, Context, Entity, EventEmitter, Global, SharedString, + Task, WeakEntity, }; use language::Capability; use rpc::{ @@ -21,9 +21,8 @@ use util::{maybe, ResultExt}; pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30); -pub fn init(client: &Arc, user_store: Model, cx: &mut AppContext) { - let channel_store = - cx.new_model(|cx| ChannelStore::new(client.clone(), user_store.clone(), cx)); +pub fn init(client: &Arc, user_store: Entity, cx: &mut App) { + let channel_store = cx.new(|cx| ChannelStore::new(client.clone(), user_store.clone(), cx)); cx.set_global(GlobalChannelStore(channel_store)); } @@ -44,7 +43,7 @@ pub struct ChannelStore { opened_chats: HashMap>, client: Arc, did_subscribe: bool, - user_store: Model, + user_store: Entity, _rpc_subscriptions: [Subscription; 2], _watch_connection_status: Task>, disconnect_channel_buffers_task: Option>, @@ -69,7 +68,7 @@ pub struct ChannelState { } impl Channel { - pub fn link(&self, cx: &AppContext) -> String { + pub fn link(&self, cx: &App) -> String { format!( "{}/channel/{}-{}", ClientSettings::get_global(cx).server_url, @@ -78,7 +77,7 @@ impl Channel { ) } - pub fn notes_link(&self, heading: Option, cx: &AppContext) -> String { + pub fn notes_link(&self, heading: Option, cx: &App) -> String { self.link(cx) + "/notes" + &heading @@ -144,24 +143,20 @@ pub enum ChannelEvent { impl EventEmitter for ChannelStore {} enum OpenedModelHandle { - Open(WeakModel), - Loading(Shared, Arc>>>), + Open(WeakEntity), + Loading(Shared, Arc>>>), } -struct GlobalChannelStore(Model); +struct GlobalChannelStore(Entity); impl Global for GlobalChannelStore {} impl ChannelStore { - pub fn global(cx: &AppContext) -> Model { + pub fn global(cx: &App) -> Entity { cx.global::().0.clone() } - pub fn new( - client: Arc, - user_store: Model, - cx: &mut ModelContext, - ) -> Self { + pub fn new(client: Arc, user_store: Entity, cx: &mut Context) -> Self { let rpc_subscriptions = [ client.add_message_handler(cx.weak_model(), Self::handle_update_channels), client.add_message_handler(cx.weak_model(), Self::handle_update_user_channels), @@ -295,7 +290,7 @@ impl ChannelStore { self.channel_index.by_id().get(&channel_id) } - pub fn has_open_channel_buffer(&self, channel_id: ChannelId, _cx: &AppContext) -> bool { + pub fn has_open_channel_buffer(&self, channel_id: ChannelId, _cx: &App) -> bool { if let Some(buffer) = self.opened_buffers.get(&channel_id) { if let OpenedModelHandle::Open(buffer) = buffer { return buffer.upgrade().is_some(); @@ -307,11 +302,11 @@ impl ChannelStore { pub fn open_channel_buffer( &mut self, channel_id: ChannelId, - cx: &mut ModelContext, - ) -> Task>> { + cx: &mut Context, + ) -> Task>> { let client = self.client.clone(); let user_store = self.user_store.clone(); - let channel_store = cx.handle(); + let channel_store = cx.model(); self.open_channel_resource( channel_id, |this| &mut this.opened_buffers, @@ -323,7 +318,7 @@ impl ChannelStore { pub fn fetch_channel_messages( &self, message_ids: Vec, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task>> { let request = if message_ids.is_empty() { None @@ -384,7 +379,7 @@ impl ChannelStore { &mut self, channel_id: ChannelId, message_id: u64, - cx: &mut ModelContext, + cx: &mut Context, ) { self.channel_states .entry(channel_id) @@ -397,7 +392,7 @@ impl ChannelStore { &mut self, channel_id: ChannelId, message_id: u64, - cx: &mut ModelContext, + cx: &mut Context, ) { self.channel_states .entry(channel_id) @@ -411,7 +406,7 @@ impl ChannelStore { channel_id: ChannelId, epoch: u64, version: &clock::Global, - cx: &mut ModelContext, + cx: &mut Context, ) { self.channel_states .entry(channel_id) @@ -425,7 +420,7 @@ impl ChannelStore { channel_id: ChannelId, epoch: u64, version: &clock::Global, - cx: &mut ModelContext, + cx: &mut Context, ) { self.channel_states .entry(channel_id) @@ -437,11 +432,11 @@ impl ChannelStore { pub fn open_channel_chat( &mut self, channel_id: ChannelId, - cx: &mut ModelContext, - ) -> Task>> { + cx: &mut Context, + ) -> Task>> { let client = self.client.clone(); let user_store = self.user_store.clone(); - let this = cx.handle(); + let this = cx.model(); self.open_channel_resource( channel_id, |this| &mut this.opened_chats, @@ -460,11 +455,11 @@ impl ChannelStore { channel_id: ChannelId, get_map: fn(&mut Self) -> &mut HashMap>, load: F, - cx: &mut ModelContext, - ) -> Task>> + cx: &mut Context, + ) -> Task>> where F: 'static + FnOnce(Arc, AsyncAppContext) -> Fut, - Fut: Future>>, + Fut: Future>>, T: 'static, { let task = loop { @@ -572,7 +567,7 @@ impl ChannelStore { &self, name: &str, parent_id: Option, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { let client = self.client.clone(); let name = name.trim_start_matches('#').to_owned(); @@ -614,7 +609,7 @@ impl ChannelStore { &mut self, channel_id: ChannelId, to: ChannelId, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { let client = self.client.clone(); cx.spawn(move |_, _| async move { @@ -633,7 +628,7 @@ impl ChannelStore { &mut self, channel_id: ChannelId, visibility: ChannelVisibility, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { let client = self.client.clone(); cx.spawn(move |_, _| async move { @@ -653,7 +648,7 @@ impl ChannelStore { channel_id: ChannelId, user_id: UserId, role: proto::ChannelRole, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { if !self.outgoing_invites.insert((channel_id, user_id)) { return Task::ready(Err(anyhow!("invite request already in progress"))); @@ -685,7 +680,7 @@ impl ChannelStore { &mut self, channel_id: ChannelId, user_id: u64, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { if !self.outgoing_invites.insert((channel_id, user_id)) { return Task::ready(Err(anyhow!("invite request already in progress"))); @@ -715,7 +710,7 @@ impl ChannelStore { channel_id: ChannelId, user_id: UserId, role: proto::ChannelRole, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { if !self.outgoing_invites.insert((channel_id, user_id)) { return Task::ready(Err(anyhow!("member request already in progress"))); @@ -746,7 +741,7 @@ impl ChannelStore { &mut self, channel_id: ChannelId, new_name: &str, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { let client = self.client.clone(); let name = new_name.to_string(); @@ -783,7 +778,7 @@ impl ChannelStore { &mut self, channel_id: ChannelId, accept: bool, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { let client = self.client.clone(); cx.background_executor().spawn(async move { @@ -801,7 +796,7 @@ impl ChannelStore { channel_id: ChannelId, query: String, limit: u16, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task>> { let client = self.client.clone(); let user_store = self.user_store.downgrade(); @@ -851,7 +846,7 @@ impl ChannelStore { } async fn handle_update_channels( - this: Model, + this: Entity, message: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result<()> { @@ -864,7 +859,7 @@ impl ChannelStore { } async fn handle_update_user_channels( - this: Model, + this: Entity, message: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result<()> { @@ -896,7 +891,7 @@ impl ChannelStore { }) } - fn handle_connect(&mut self, cx: &mut ModelContext) -> Task> { + fn handle_connect(&mut self, cx: &mut Context) -> Task> { self.channel_index.clear(); self.channel_invitations.clear(); self.channel_participants.clear(); @@ -1011,7 +1006,7 @@ impl ChannelStore { }) } - fn handle_disconnect(&mut self, wait_for_reconnect: bool, cx: &mut ModelContext) { + fn handle_disconnect(&mut self, wait_for_reconnect: bool, cx: &mut Context) { cx.notify(); self.did_subscribe = false; self.disconnect_channel_buffers_task.get_or_insert_with(|| { @@ -1039,7 +1034,7 @@ impl ChannelStore { pub(crate) fn update_channels( &mut self, payload: proto::UpdateChannels, - cx: &mut ModelContext, + cx: &mut Context, ) -> Option>> { if !payload.remove_channel_invitations.is_empty() { self.channel_invitations diff --git a/crates/channel/src/channel_store_tests.rs b/crates/channel/src/channel_store_tests.rs index ef657d3739..779849df24 100644 --- a/crates/channel/src/channel_store_tests.rs +++ b/crates/channel/src/channel_store_tests.rs @@ -3,13 +3,13 @@ use crate::channel_chat::ChannelChatEvent; use super::*; use client::{test::FakeServer, Client, UserStore}; use clock::FakeSystemClock; -use gpui::{AppContext, Context, Model, SemanticVersion, TestAppContext}; +use gpui::{App, AppContext as _, Entity, SemanticVersion, TestAppContext}; use http_client::FakeHttpClient; use rpc::proto::{self}; use settings::SettingsStore; #[gpui::test] -fn test_update_channels(cx: &mut AppContext) { +fn test_update_channels(cx: &mut App) { let channel_store = init_test(cx); update_channels( @@ -77,7 +77,7 @@ fn test_update_channels(cx: &mut AppContext) { } #[gpui::test] -fn test_dangling_channel_paths(cx: &mut AppContext) { +fn test_dangling_channel_paths(cx: &mut App) { let channel_store = init_test(cx); update_channels( @@ -343,7 +343,7 @@ async fn test_channel_messages(cx: &mut TestAppContext) { }); } -fn init_test(cx: &mut AppContext) -> Model { +fn init_test(cx: &mut App) -> Entity { let settings_store = SettingsStore::test(cx); cx.set_global(settings_store); release_channel::init(SemanticVersion::default(), cx); @@ -352,7 +352,7 @@ fn init_test(cx: &mut AppContext) -> Model { let clock = Arc::new(FakeSystemClock::new()); let http = FakeHttpClient::with_404_response(); let client = Client::new(clock, http.clone(), cx); - let user_store = cx.new_model(|cx| UserStore::new(client.clone(), cx)); + let user_store = cx.new(|cx| UserStore::new(client.clone(), cx)); client::init(&client, cx); crate::init(&client, user_store, cx); @@ -361,9 +361,9 @@ fn init_test(cx: &mut AppContext) -> Model { } fn update_channels( - channel_store: &Model, + channel_store: &Entity, message: proto::UpdateChannels, - cx: &mut AppContext, + cx: &mut App, ) { let task = channel_store.update(cx, |store, cx| store.update_channels(message, cx)); assert!(task.is_none()); @@ -371,9 +371,9 @@ fn update_channels( #[track_caller] fn assert_channels( - channel_store: &Model, + channel_store: &Entity, expected_channels: &[(usize, String)], - cx: &mut AppContext, + cx: &mut App, ) { let actual = channel_store.update(cx, |store, _| { store diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 2ecda7d869..5585709d56 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -3,7 +3,7 @@ allow(dead_code) )] -use anyhow::{Context, Result}; +use anyhow::{Context as _, Result}; use clap::Parser; use cli::{ipc::IpcOneShotServer, CliRequest, CliResponse, IpcHandshake}; use collections::HashMap; @@ -536,7 +536,7 @@ mod windows { #[cfg(target_os = "macos")] mod mac_os { - use anyhow::{anyhow, Context, Result}; + use anyhow::{anyhow, Context as _, Result}; use core_foundation::{ array::{CFArray, CFIndex}, string::kCFStringEncodingUTF8, diff --git a/crates/client/src/client.rs b/crates/client/src/client.rs index f64dbc110e..c5b5c6634e 100644 --- a/crates/client/src/client.rs +++ b/crates/client/src/client.rs @@ -19,7 +19,7 @@ use futures::{ channel::oneshot, future::BoxFuture, AsyncReadExt, FutureExt, SinkExt, Stream, StreamExt, TryFutureExt as _, TryStreamExt, }; -use gpui::{actions, AppContext, AsyncAppContext, Global, Model, Task, WeakModel}; +use gpui::{actions, App, AsyncAppContext, Entity, Global, Task, WeakEntity}; use http_client::{AsyncBody, HttpClient, HttpClientWithUrl}; use parking_lot::RwLock; use postage::watch; @@ -104,7 +104,7 @@ impl Settings for ClientSettings { type FileContent = ClientSettingsContent; - fn load(sources: SettingsSources, _: &mut AppContext) -> Result { + fn load(sources: SettingsSources, _: &mut App) -> Result { let mut result = sources.json_merge::()?; if let Some(server_url) = &*ZED_SERVER_URL { result.server_url.clone_from(server_url) @@ -128,7 +128,7 @@ impl Settings for ProxySettings { type FileContent = ProxySettingsContent; - fn load(sources: SettingsSources, _: &mut AppContext) -> Result { + fn load(sources: SettingsSources, _: &mut App) -> Result { Ok(Self { proxy: sources .user @@ -139,13 +139,13 @@ impl Settings for ProxySettings { } } -pub fn init_settings(cx: &mut AppContext) { +pub fn init_settings(cx: &mut App) { TelemetrySettings::register(cx); ClientSettings::register(cx); ProxySettings::register(cx); } -pub fn init(client: &Arc, cx: &mut AppContext) { +pub fn init(client: &Arc, cx: &mut App) { let client = Arc::downgrade(client); cx.on_action({ let client = client.clone(); @@ -380,7 +380,7 @@ pub struct PendingEntitySubscription { } impl PendingEntitySubscription { - pub fn set_model(mut self, model: &Model, cx: &AsyncAppContext) -> Subscription { + pub fn set_model(mut self, model: &Entity, cx: &AsyncAppContext) -> Subscription { self.consumed = true; let mut handlers = self.client.handler_set.lock(); let id = (TypeId::of::(), self.remote_id); @@ -456,7 +456,7 @@ impl settings::Settings for TelemetrySettings { type FileContent = TelemetrySettingsContent; - fn load(sources: SettingsSources, _: &mut AppContext) -> Result { + fn load(sources: SettingsSources, _: &mut App) -> Result { Ok(Self { diagnostics: sources .user @@ -483,7 +483,7 @@ impl Client { pub fn new( clock: Arc, http: Arc, - cx: &mut AppContext, + cx: &mut App, ) -> Arc { let use_zed_development_auth = match ReleaseChannel::try_global(cx) { Some(ReleaseChannel::Dev) => *ZED_DEVELOPMENT_AUTH, @@ -518,7 +518,7 @@ impl Client { }) } - pub fn production(cx: &mut AppContext) -> Arc { + pub fn production(cx: &mut App) -> Arc { let clock = Arc::new(clock::RealSystemClock); let http = Arc::new(HttpClientWithUrl::new_uri( cx.http_client(), @@ -576,10 +576,10 @@ impl Client { self } - pub fn global(cx: &AppContext) -> Arc { + pub fn global(cx: &App) -> Arc { cx.global::().0.clone() } - pub fn set_global(client: Arc, cx: &mut AppContext) { + pub fn set_global(client: Arc, cx: &mut App) { cx.set_global(GlobalClient(client)) } @@ -678,13 +678,13 @@ impl Client { #[track_caller] pub fn add_message_handler( self: &Arc, - entity: WeakModel, + entity: WeakEntity, handler: H, ) -> Subscription where M: EnvelopedMessage, E: 'static, - H: 'static + Sync + Fn(Model, TypedEnvelope, AsyncAppContext) -> F + Send + Sync, + H: 'static + Sync + Fn(Entity, TypedEnvelope, AsyncAppContext) -> F + Send + Sync, F: 'static + Future>, { self.add_message_handler_impl(entity, move |model, message, _, cx| { @@ -694,7 +694,7 @@ impl Client { fn add_message_handler_impl( self: &Arc, - entity: WeakModel, + entity: WeakEntity, handler: H, ) -> Subscription where @@ -702,7 +702,7 @@ impl Client { E: 'static, H: 'static + Sync - + Fn(Model, TypedEnvelope, AnyProtoClient, AsyncAppContext) -> F + + Fn(Entity, TypedEnvelope, AnyProtoClient, AsyncAppContext) -> F + Send + Sync, F: 'static + Future>, @@ -739,13 +739,13 @@ impl Client { pub fn add_request_handler( self: &Arc, - model: WeakModel, + model: WeakEntity, handler: H, ) -> Subscription where M: RequestMessage, E: 'static, - H: 'static + Sync + Fn(Model, TypedEnvelope, AsyncAppContext) -> F + Send + Sync, + H: 'static + Sync + Fn(Entity, TypedEnvelope, AsyncAppContext) -> F + Send + Sync, F: 'static + Future>, { self.add_message_handler_impl(model, move |handle, envelope, this, cx| { @@ -1751,7 +1751,7 @@ pub const ZED_URL_SCHEME: &str = "zed"; /// /// Returns a [`Some`] containing the unprefixed link if the link is a Zed link. /// Returns [`None`] otherwise. -pub fn parse_zed_link<'a>(link: &'a str, cx: &AppContext) -> Option<&'a str> { +pub fn parse_zed_link<'a>(link: &'a str, cx: &App) -> Option<&'a str> { let server_url = &ClientSettings::get_global(cx).server_url; if let Some(stripped) = link .strip_prefix(server_url) @@ -1775,7 +1775,7 @@ mod tests { use crate::test::FakeServer; use clock::FakeSystemClock; - use gpui::{BackgroundExecutor, Context, TestAppContext}; + use gpui::{AppContext as _, BackgroundExecutor, TestAppContext}; use http_client::FakeHttpClient; use parking_lot::Mutex; use proto::TypedEnvelope; @@ -1961,7 +1961,7 @@ mod tests { let (done_tx1, done_rx1) = smol::channel::unbounded(); let (done_tx2, done_rx2) = smol::channel::unbounded(); AnyProtoClient::from(client.clone()).add_model_message_handler( - move |model: Model, _: TypedEnvelope, mut cx| { + move |model: Entity, _: TypedEnvelope, mut cx| { match model.update(&mut cx, |model, _| model.id).unwrap() { 1 => done_tx1.try_send(()).unwrap(), 2 => done_tx2.try_send(()).unwrap(), @@ -1970,15 +1970,15 @@ mod tests { async { Ok(()) } }, ); - let model1 = cx.new_model(|_| TestModel { + let model1 = cx.new(|_| TestModel { id: 1, subscription: None, }); - let model2 = cx.new_model(|_| TestModel { + let model2 = cx.new(|_| TestModel { id: 2, subscription: None, }); - let model3 = cx.new_model(|_| TestModel { + let model3 = cx.new(|_| TestModel { id: 3, subscription: None, }); @@ -2018,7 +2018,7 @@ mod tests { }); let server = FakeServer::for_client(user_id, &client, cx).await; - let model = cx.new_model(|_| TestModel::default()); + let model = cx.new(|_| TestModel::default()); let (done_tx1, _done_rx1) = smol::channel::unbounded(); let (done_tx2, done_rx2) = smol::channel::unbounded(); let subscription1 = client.add_message_handler( @@ -2053,11 +2053,11 @@ mod tests { }); let server = FakeServer::for_client(user_id, &client, cx).await; - let model = cx.new_model(|_| TestModel::default()); + let model = cx.new(|_| TestModel::default()); let (done_tx, done_rx) = smol::channel::unbounded(); let subscription = client.add_message_handler( model.clone().downgrade(), - move |model: Model, _: TypedEnvelope, mut cx| { + move |model: Entity, _: TypedEnvelope, mut cx| { model .update(&mut cx, |model, _| model.subscription.take()) .unwrap(); diff --git a/crates/client/src/telemetry.rs b/crates/client/src/telemetry.rs index 26f793ba57..56ed6e6c03 100644 --- a/crates/client/src/telemetry.rs +++ b/crates/client/src/telemetry.rs @@ -6,7 +6,7 @@ use clock::SystemClock; use collections::{HashMap, HashSet}; use futures::channel::mpsc; use futures::{Future, StreamExt}; -use gpui::{AppContext, BackgroundExecutor, Task}; +use gpui::{App, BackgroundExecutor, Task}; use http_client::{self, AsyncBody, HttpClient, HttpClientWithUrl, Method, Request}; use parking_lot::Mutex; use release_channel::ReleaseChannel; @@ -178,7 +178,7 @@ impl Telemetry { pub fn new( clock: Arc, client: Arc, - cx: &mut AppContext, + cx: &mut App, ) -> Arc { let release_channel = ReleaseChannel::try_global(cx).map(|release_channel| release_channel.display_name()); @@ -299,7 +299,7 @@ impl Telemetry { system_id: Option, installation_id: Option, session_id: String, - cx: &AppContext, + cx: &App, ) { let mut state = self.state.lock(); state.system_id = system_id.map(|id| id.into()); diff --git a/crates/client/src/test.rs b/crates/client/src/test.rs index 5a93c5edd9..4b158b6ab1 100644 --- a/crates/client/src/test.rs +++ b/crates/client/src/test.rs @@ -2,7 +2,7 @@ use crate::{Client, Connection, Credentials, EstablishConnectionError, UserStore use anyhow::{anyhow, Result}; use chrono::Duration; use futures::{stream::BoxStream, StreamExt}; -use gpui::{BackgroundExecutor, Context, Model, TestAppContext}; +use gpui::{AppContext as _, BackgroundExecutor, Entity, TestAppContext}; use parking_lot::Mutex; use rpc::{ proto::{self, GetPrivateUserInfo, GetPrivateUserInfoResponse}, @@ -203,8 +203,8 @@ impl FakeServer { &self, client: Arc, cx: &mut TestAppContext, - ) -> Model { - let user_store = cx.new_model(|cx| UserStore::new(client, cx)); + ) -> Entity { + let user_store = cx.new(|cx| UserStore::new(client, cx)); assert_eq!( self.receive::() .await diff --git a/crates/client/src/user.rs b/crates/client/src/user.rs index 2427bc4c40..39dacb9700 100644 --- a/crates/client/src/user.rs +++ b/crates/client/src/user.rs @@ -1,12 +1,11 @@ use super::{proto, Client, Status, TypedEnvelope}; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, Context as _, Result}; use chrono::{DateTime, Utc}; use collections::{hash_map::Entry, HashMap, HashSet}; use feature_flags::FeatureFlagAppExt; use futures::{channel::mpsc, Future, StreamExt}; use gpui::{ - AppContext, AsyncAppContext, EventEmitter, Model, ModelContext, SharedString, SharedUri, Task, - WeakModel, + App, AsyncAppContext, Context, Entity, EventEmitter, SharedString, SharedUri, Task, WeakEntity, }; use postage::{sink::Sink, watch}; use rpc::proto::{RequestMessage, UsersResponse}; @@ -106,7 +105,7 @@ pub struct UserStore { client: Weak, _maintain_contacts: Task<()>, _maintain_current_user: Task>, - weak_self: WeakModel, + weak_self: WeakEntity, } #[derive(Clone)] @@ -143,7 +142,7 @@ enum UpdateContacts { } impl UserStore { - pub fn new(client: Arc, cx: &ModelContext) -> Self { + pub fn new(client: Arc, cx: &Context) -> Self { let (mut current_user_tx, current_user_rx) = watch::channel(); let (update_contacts_tx, mut update_contacts_rx) = mpsc::unbounded(); let rpc_subscriptions = vec![ @@ -274,7 +273,7 @@ impl UserStore { } async fn handle_update_invite_info( - this: Model, + this: Entity, message: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result<()> { @@ -289,7 +288,7 @@ impl UserStore { } async fn handle_show_contacts( - this: Model, + this: Entity, _: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result<()> { @@ -302,7 +301,7 @@ impl UserStore { } async fn handle_update_contacts( - this: Model, + this: Entity, message: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result<()> { @@ -315,7 +314,7 @@ impl UserStore { } async fn handle_update_plan( - this: Model, + this: Entity, message: TypedEnvelope, mut cx: AsyncAppContext, ) -> Result<()> { @@ -326,11 +325,7 @@ impl UserStore { Ok(()) } - fn update_contacts( - &mut self, - message: UpdateContacts, - cx: &ModelContext, - ) -> Task> { + fn update_contacts(&mut self, message: UpdateContacts, cx: &Context) -> Task> { match message { UpdateContacts::Wait(barrier) => { drop(barrier); @@ -504,16 +499,12 @@ impl UserStore { pub fn request_contact( &mut self, responder_id: u64, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { self.perform_contact_request(responder_id, proto::RequestContact { responder_id }, cx) } - pub fn remove_contact( - &mut self, - user_id: u64, - cx: &mut ModelContext, - ) -> Task> { + pub fn remove_contact(&mut self, user_id: u64, cx: &mut Context) -> Task> { self.perform_contact_request(user_id, proto::RemoveContact { user_id }, cx) } @@ -527,7 +518,7 @@ impl UserStore { &mut self, requester_id: u64, accept: bool, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { self.perform_contact_request( requester_id, @@ -546,7 +537,7 @@ impl UserStore { pub fn dismiss_contact_request( &self, requester_id: u64, - cx: &ModelContext, + cx: &Context, ) -> Task> { let client = self.client.upgrade(); cx.spawn(move |_, _| async move { @@ -565,7 +556,7 @@ impl UserStore { &mut self, user_id: u64, request: T, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { let client = self.client.upgrade(); *self.pending_contact_requests.entry(user_id).or_insert(0) += 1; @@ -615,7 +606,7 @@ impl UserStore { pub fn get_users( &self, user_ids: Vec, - cx: &ModelContext, + cx: &Context, ) -> Task>>> { let mut user_ids_to_fetch = user_ids.clone(); user_ids_to_fetch.retain(|id| !self.users.contains_key(id)); @@ -650,7 +641,7 @@ impl UserStore { pub fn fuzzy_search_users( &self, query: String, - cx: &ModelContext, + cx: &Context, ) -> Task>>> { self.load_users(proto::FuzzySearchUsers { query }, cx) } @@ -659,7 +650,7 @@ impl UserStore { self.users.get(&user_id).cloned() } - pub fn get_user_optimistic(&self, user_id: u64, cx: &ModelContext) -> Option> { + pub fn get_user_optimistic(&self, user_id: u64, cx: &Context) -> Option> { if let Some(user) = self.users.get(&user_id).cloned() { return Some(user); } @@ -668,7 +659,7 @@ impl UserStore { None } - pub fn get_user(&self, user_id: u64, cx: &ModelContext) -> Task>> { + pub fn get_user(&self, user_id: u64, cx: &Context) -> Task>> { if let Some(user) = self.users.get(&user_id).cloned() { return Task::ready(Ok(user)); } @@ -708,7 +699,7 @@ impl UserStore { .map(|accepted_tos_at| accepted_tos_at.is_some()) } - pub fn accept_terms_of_service(&self, cx: &ModelContext) -> Task> { + pub fn accept_terms_of_service(&self, cx: &Context) -> Task> { if self.current_user().is_none() { return Task::ready(Err(anyhow!("no current user"))); }; @@ -740,7 +731,7 @@ impl UserStore { fn load_users( &self, request: impl RequestMessage, - cx: &ModelContext, + cx: &Context, ) -> Task>>> { let client = self.client.clone(); cx.spawn(|this, mut cx| async move { @@ -774,7 +765,7 @@ impl UserStore { pub fn set_participant_indices( &mut self, participant_indices: HashMap, - cx: &mut ModelContext, + cx: &mut Context, ) { if participant_indices != self.participant_indices { self.participant_indices = participant_indices; @@ -789,7 +780,7 @@ impl UserStore { pub fn participant_names( &self, user_ids: impl Iterator, - cx: &AppContext, + cx: &App, ) -> HashMap { let mut ret = HashMap::default(); let mut missing_user_ids = Vec::new(); @@ -827,7 +818,7 @@ impl User { impl Contact { async fn from_proto( contact: proto::Contact, - user_store: &Model, + user_store: &Entity, cx: &mut AsyncAppContext, ) -> Result { let user = user_store diff --git a/crates/client/src/zed_urls.rs b/crates/client/src/zed_urls.rs index a5b27cf288..bfdae468fb 100644 --- a/crates/client/src/zed_urls.rs +++ b/crates/client/src/zed_urls.rs @@ -4,16 +4,16 @@ //! links appropriate for the environment (e.g., by linking to a local copy of //! zed.dev in development). -use gpui::AppContext; +use gpui::App; use settings::Settings; use crate::ClientSettings; -fn server_url(cx: &AppContext) -> &str { +fn server_url(cx: &App) -> &str { &ClientSettings::get_global(cx).server_url } /// Returns the URL to the account page on zed.dev. -pub fn account_url(cx: &AppContext) -> String { +pub fn account_url(cx: &App) -> String { format!("{server_url}/account", server_url = server_url(cx)) } diff --git a/crates/collab/src/auth.rs b/crates/collab/src/auth.rs index bd60ee0cd0..b5cf278f70 100644 --- a/crates/collab/src/auth.rs +++ b/crates/collab/src/auth.rs @@ -3,7 +3,7 @@ use crate::{ rpc::Principal, AppState, Error, Result, }; -use anyhow::{anyhow, Context}; +use anyhow::{anyhow, Context as _}; use axum::{ http::{self, Request, StatusCode}, middleware::Next, diff --git a/crates/collab/src/main.rs b/crates/collab/src/main.rs index 9e5c3dd048..d552bba68e 100644 --- a/crates/collab/src/main.rs +++ b/crates/collab/src/main.rs @@ -6,6 +6,7 @@ use axum::{ routing::get, Extension, Router, }; + use collab::api::billing::sync_llm_usage_with_stripe_periodically; use collab::api::CloudflareIpCountryHeader; use collab::llm::{db::LlmDatabase, log_usage_periodically}; diff --git a/crates/collab/src/seed.rs b/crates/collab/src/seed.rs index d57fc9a256..ce5d99bbe0 100644 --- a/crates/collab/src/seed.rs +++ b/crates/collab/src/seed.rs @@ -1,6 +1,6 @@ use crate::db::{self, ChannelRole, NewUserParams}; -use anyhow::Context; +use anyhow::Context as _; use chrono::{DateTime, Utc}; use db::Database; use serde::{de::DeserializeOwned, Deserialize}; diff --git a/crates/collab/src/stripe_billing.rs b/crates/collab/src/stripe_billing.rs index 126db988a1..9f561ab1b2 100644 --- a/crates/collab/src/stripe_billing.rs +++ b/crates/collab/src/stripe_billing.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use crate::{llm, Cents, Result}; -use anyhow::Context; +use anyhow::Context as _; use chrono::{Datelike, Utc}; use collections::HashMap; use serde::{Deserialize, Serialize}; diff --git a/crates/collab/src/tests.rs b/crates/collab/src/tests.rs index 2ce69efc9b..20fa289389 100644 --- a/crates/collab/src/tests.rs +++ b/crates/collab/src/tests.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use call::Room; use client::ChannelId; -use gpui::{Model, TestAppContext}; +use gpui::{Entity, TestAppContext}; mod channel_buffer_tests; mod channel_guest_tests; @@ -33,7 +33,7 @@ struct RoomParticipants { pending: Vec, } -fn room_participants(room: &Model, cx: &mut TestAppContext) -> RoomParticipants { +fn room_participants(room: &Entity, cx: &mut TestAppContext) -> RoomParticipants { room.read_with(cx, |room, _| { let mut remote = room .remote_participants() @@ -51,7 +51,7 @@ fn room_participants(room: &Model, cx: &mut TestAppContext) -> RoomPartici }) } -fn channel_id(room: &Model, cx: &mut TestAppContext) -> Option { +fn channel_id(room: &Entity, cx: &mut TestAppContext) -> Option { cx.read(|cx| room.read(cx).channel_id()) } diff --git a/crates/collab/src/tests/channel_buffer_tests.rs b/crates/collab/src/tests/channel_buffer_tests.rs index b5bfd0f03b..83bb8966b7 100644 --- a/crates/collab/src/tests/channel_buffer_tests.rs +++ b/crates/collab/src/tests/channel_buffer_tests.rs @@ -9,7 +9,7 @@ use collab_ui::channel_view::ChannelView; use collections::HashMap; use editor::{Anchor, Editor, ToOffset}; use futures::future; -use gpui::{BackgroundExecutor, Model, TestAppContext, ViewContext}; +use gpui::{BackgroundExecutor, Context, Entity, TestAppContext, Window}; use rpc::{proto::PeerId, RECEIVE_TIMEOUT}; use serde_json::json; use std::ops::Range; @@ -161,43 +161,43 @@ async fn test_channel_notes_participant_indices( // Clients A, B, and C open the channel notes let channel_view_a = cx_a - .update(|cx| ChannelView::open(channel_id, None, workspace_a.clone(), cx)) + .update(|window, cx| ChannelView::open(channel_id, None, workspace_a.clone(), window, cx)) .await .unwrap(); let channel_view_b = cx_b - .update(|cx| ChannelView::open(channel_id, None, workspace_b.clone(), cx)) + .update(|window, cx| ChannelView::open(channel_id, None, workspace_b.clone(), window, cx)) .await .unwrap(); let channel_view_c = cx_c - .update(|cx| ChannelView::open(channel_id, None, workspace_c.clone(), cx)) + .update(|window, cx| ChannelView::open(channel_id, None, workspace_c.clone(), window, cx)) .await .unwrap(); // Clients A, B, and C all insert and select some text - channel_view_a.update(cx_a, |notes, cx| { + channel_view_a.update_in(cx_a, |notes, window, cx| { notes.editor.update(cx, |editor, cx| { - editor.insert("a", cx); - editor.change_selections(None, cx, |selections| { + editor.insert("a", window, cx); + editor.change_selections(None, window, cx, |selections| { selections.select_ranges(vec![0..1]); }); }); }); executor.run_until_parked(); - channel_view_b.update(cx_b, |notes, cx| { + channel_view_b.update_in(cx_b, |notes, window, cx| { notes.editor.update(cx, |editor, cx| { - editor.move_down(&Default::default(), cx); - editor.insert("b", cx); - editor.change_selections(None, cx, |selections| { + editor.move_down(&Default::default(), window, cx); + editor.insert("b", window, cx); + editor.change_selections(None, window, cx, |selections| { selections.select_ranges(vec![1..2]); }); }); }); executor.run_until_parked(); - channel_view_c.update(cx_c, |notes, cx| { + channel_view_c.update_in(cx_c, |notes, window, cx| { notes.editor.update(cx, |editor, cx| { - editor.move_down(&Default::default(), cx); - editor.insert("c", cx); - editor.change_selections(None, cx, |selections| { + editor.move_down(&Default::default(), window, cx); + editor.insert("c", window, cx); + editor.change_selections(None, window, cx, |selections| { selections.select_ranges(vec![2..3]); }); }); @@ -206,9 +206,9 @@ async fn test_channel_notes_participant_indices( // Client A sees clients B and C without assigned colors, because they aren't // in a call together. executor.run_until_parked(); - channel_view_a.update(cx_a, |notes, cx| { + channel_view_a.update_in(cx_a, |notes, window, cx| { notes.editor.update(cx, |editor, cx| { - assert_remote_selections(editor, &[(None, 1..2), (None, 2..3)], cx); + assert_remote_selections(editor, &[(None, 1..2), (None, 2..3)], window, cx); }); }); @@ -222,20 +222,22 @@ async fn test_channel_notes_participant_indices( // Clients A and B see each other with two different assigned colors. Client C // still doesn't have a color. executor.run_until_parked(); - channel_view_a.update(cx_a, |notes, cx| { + channel_view_a.update_in(cx_a, |notes, window, cx| { notes.editor.update(cx, |editor, cx| { assert_remote_selections( editor, &[(Some(ParticipantIndex(1)), 1..2), (None, 2..3)], + window, cx, ); }); }); - channel_view_b.update(cx_b, |notes, cx| { + channel_view_b.update_in(cx_b, |notes, window, cx| { notes.editor.update(cx, |editor, cx| { assert_remote_selections( editor, &[(Some(ParticipantIndex(0)), 0..1), (None, 2..3)], + window, cx, ); }); @@ -252,8 +254,8 @@ async fn test_channel_notes_participant_indices( // Clients A and B open the same file. executor.start_waiting(); let editor_a = workspace_a - .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id_a, "file.txt"), None, true, cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.open_path((worktree_id_a, "file.txt"), None, true, window, cx) }) .await .unwrap() @@ -261,32 +263,32 @@ async fn test_channel_notes_participant_indices( .unwrap(); executor.start_waiting(); let editor_b = workspace_b - .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id_a, "file.txt"), None, true, cx) + .update_in(cx_b, |workspace, window, cx| { + workspace.open_path((worktree_id_a, "file.txt"), None, true, window, cx) }) .await .unwrap() .downcast::() .unwrap(); - editor_a.update(cx_a, |editor, cx| { - editor.change_selections(None, cx, |selections| { + editor_a.update_in(cx_a, |editor, window, cx| { + editor.change_selections(None, window, cx, |selections| { selections.select_ranges(vec![0..1]); }); }); - editor_b.update(cx_b, |editor, cx| { - editor.change_selections(None, cx, |selections| { + editor_b.update_in(cx_b, |editor, window, cx| { + editor.change_selections(None, window, cx, |selections| { selections.select_ranges(vec![2..3]); }); }); executor.run_until_parked(); // Clients A and B see each other with the same colors as in the channel notes. - editor_a.update(cx_a, |editor, cx| { - assert_remote_selections(editor, &[(Some(ParticipantIndex(1)), 2..3)], cx); + editor_a.update_in(cx_a, |editor, window, cx| { + assert_remote_selections(editor, &[(Some(ParticipantIndex(1)), 2..3)], window, cx); }); - editor_b.update(cx_b, |editor, cx| { - assert_remote_selections(editor, &[(Some(ParticipantIndex(0)), 0..1)], cx); + editor_b.update_in(cx_b, |editor, window, cx| { + assert_remote_selections(editor, &[(Some(ParticipantIndex(0)), 0..1)], window, cx); }); } @@ -294,9 +296,10 @@ async fn test_channel_notes_participant_indices( fn assert_remote_selections( editor: &mut Editor, expected_selections: &[(Option, Range)], - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - let snapshot = editor.snapshot(cx); + let snapshot = editor.snapshot(window, cx); let range = Anchor::min()..Anchor::max(); let remote_selections = snapshot .remote_selections_in_range(&range, editor.collaboration_hub().unwrap(), cx) @@ -641,9 +644,9 @@ async fn test_channel_buffer_changes( }); // Closing the buffer should re-enable change tracking - cx_b.update(|cx| { + cx_b.update(|window, cx| { workspace_b.update(cx, |workspace, cx| { - workspace.close_all_items_and_panes(&Default::default(), cx) + workspace.close_all_items_and_panes(&Default::default(), window, cx) }); }); deterministic.run_until_parked(); @@ -691,6 +694,6 @@ fn assert_collaborators(collaborators: &HashMap, ids: &[Op ); } -fn buffer_text(channel_buffer: &Model, cx: &mut TestAppContext) -> String { +fn buffer_text(channel_buffer: &Entity, cx: &mut TestAppContext) -> String { channel_buffer.read_with(cx, |buffer, _| buffer.text()) } diff --git a/crates/collab/src/tests/channel_guest_tests.rs b/crates/collab/src/tests/channel_guest_tests.rs index ebde1d9e50..0e8d856221 100644 --- a/crates/collab/src/tests/channel_guest_tests.rs +++ b/crates/collab/src/tests/channel_guest_tests.rs @@ -107,7 +107,7 @@ async fn test_channel_guest_promotion(cx_a: &mut TestAppContext, cx_b: &mut Test }); assert!(project_b.read_with(cx_b, |project, cx| project.is_read_only(cx))); assert!(editor_b.update(cx_b, |e, cx| e.read_only(cx))); - cx_b.update(|cx_b| { + cx_b.update(|_window, cx_b| { assert!(room_b.read_with(cx_b, |room, _| !room.can_use_microphone())); }); assert!(room_b @@ -135,7 +135,7 @@ async fn test_channel_guest_promotion(cx_a: &mut TestAppContext, cx_b: &mut Test assert!(editor_b.update(cx_b, |editor, cx| !editor.read_only(cx))); // B sees themselves as muted, and can unmute. - cx_b.update(|cx_b| { + cx_b.update(|_window, cx_b| { assert!(room_b.read_with(cx_b, |room, _| room.can_use_microphone())); }); room_b.read_with(cx_b, |room, _| assert!(room.is_muted())); diff --git a/crates/collab/src/tests/channel_message_tests.rs b/crates/collab/src/tests/channel_message_tests.rs index 08d2ae7ed1..dbc5cd86c2 100644 --- a/crates/collab/src/tests/channel_message_tests.rs +++ b/crates/collab/src/tests/channel_message_tests.rs @@ -1,7 +1,7 @@ use crate::{rpc::RECONNECT_TIMEOUT, tests::TestServer}; use channel::{ChannelChat, ChannelMessageId, MessageParams}; use collab_ui::chat_panel::ChatPanel; -use gpui::{BackgroundExecutor, Model, TestAppContext}; +use gpui::{BackgroundExecutor, Entity, TestAppContext}; use rpc::Notification; use workspace::dock::Panel; @@ -295,7 +295,7 @@ async fn test_remove_channel_message( } #[track_caller] -fn assert_messages(chat: &Model, messages: &[&str], cx: &mut TestAppContext) { +fn assert_messages(chat: &Entity, messages: &[&str], cx: &mut TestAppContext) { assert_eq!( chat.read_with(cx, |chat, _| { chat.messages() @@ -356,10 +356,10 @@ async fn test_channel_message_changes( let project_b = client_b.build_empty_local_project(cx_b); let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b); - let chat_panel_b = workspace_b.update(cx_b, ChatPanel::new); + let chat_panel_b = workspace_b.update_in(cx_b, ChatPanel::new); chat_panel_b - .update(cx_b, |chat_panel, cx| { - chat_panel.set_active(true, cx); + .update_in(cx_b, |chat_panel, window, cx| { + chat_panel.set_active(true, window, cx); chat_panel.select_channel(channel_id, None, cx) }) .await @@ -367,7 +367,7 @@ async fn test_channel_message_changes( executor.run_until_parked(); - let b_has_messages = cx_b.update(|cx| { + let b_has_messages = cx_b.update(|_, cx| { client_b .channel_store() .read(cx) @@ -384,7 +384,7 @@ async fn test_channel_message_changes( executor.run_until_parked(); - let b_has_messages = cx_b.update(|cx| { + let b_has_messages = cx_b.update(|_, cx| { client_b .channel_store() .read(cx) @@ -394,8 +394,8 @@ async fn test_channel_message_changes( assert!(!b_has_messages); // Sending a message while the chat is closed should change the flag. - chat_panel_b.update(cx_b, |chat_panel, cx| { - chat_panel.set_active(false, cx); + chat_panel_b.update_in(cx_b, |chat_panel, window, cx| { + chat_panel.set_active(false, window, cx); }); // Sending a message while the chat is open should not change the flag. @@ -406,7 +406,7 @@ async fn test_channel_message_changes( executor.run_until_parked(); - let b_has_messages = cx_b.update(|cx| { + let b_has_messages = cx_b.update(|_, cx| { client_b .channel_store() .read(cx) @@ -416,7 +416,7 @@ async fn test_channel_message_changes( assert!(b_has_messages); // Closing the chat should re-enable change tracking - cx_b.update(|_| drop(chat_panel_b)); + cx_b.update(|_, _| drop(chat_panel_b)); channel_chat_a .update(cx_a, |c, cx| c.send_message("four".into(), cx).unwrap()) @@ -425,7 +425,7 @@ async fn test_channel_message_changes( executor.run_until_parked(); - let b_has_messages = cx_b.update(|cx| { + let b_has_messages = cx_b.update(|_, cx| { client_b .channel_store() .read(cx) diff --git a/crates/collab/src/tests/channel_tests.rs b/crates/collab/src/tests/channel_tests.rs index d9fdab71e8..74b3f79d64 100644 --- a/crates/collab/src/tests/channel_tests.rs +++ b/crates/collab/src/tests/channel_tests.rs @@ -7,7 +7,7 @@ use call::ActiveCall; use channel::{ChannelMembership, ChannelStore}; use client::{ChannelId, User}; use futures::future::try_join_all; -use gpui::{BackgroundExecutor, Model, SharedString, TestAppContext}; +use gpui::{BackgroundExecutor, Entity, SharedString, TestAppContext}; use rpc::{ proto::{self, ChannelRole}, RECEIVE_TIMEOUT, @@ -1401,7 +1401,7 @@ struct ExpectedChannel { #[track_caller] fn assert_channel_invitations( - channel_store: &Model, + channel_store: &Entity, cx: &TestAppContext, expected_channels: &[ExpectedChannel], ) { @@ -1423,7 +1423,7 @@ fn assert_channel_invitations( #[track_caller] fn assert_channels( - channel_store: &Model, + channel_store: &Entity, cx: &TestAppContext, expected_channels: &[ExpectedChannel], ) { @@ -1444,7 +1444,7 @@ fn assert_channels( #[track_caller] fn assert_channels_list_shape( - channel_store: &Model, + channel_store: &Entity, cx: &TestAppContext, expected_channels: &[(ChannelId, usize)], ) { diff --git a/crates/collab/src/tests/editor_tests.rs b/crates/collab/src/tests/editor_tests.rs index 75e7c6825f..86b133c082 100644 --- a/crates/collab/src/tests/editor_tests.rs +++ b/crates/collab/src/tests/editor_tests.rs @@ -81,14 +81,21 @@ async fn test_host_disconnect( assert!(worktree_a.read_with(cx_a, |tree, _| tree.has_update_observer())); - let workspace_b = cx_b - .add_window(|cx| Workspace::new(None, project_b.clone(), client_b.app_state.clone(), cx)); + let workspace_b = cx_b.add_window(|window, cx| { + Workspace::new( + None, + project_b.clone(), + client_b.app_state.clone(), + window, + cx, + ) + }); let cx_b = &mut VisualTestContext::from_window(*workspace_b, cx_b); - let workspace_b_view = workspace_b.root_view(cx_b).unwrap(); + let workspace_b_view = workspace_b.root_model(cx_b).unwrap(); let editor_b = workspace_b - .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "b.txt"), None, true, cx) + .update(cx_b, |workspace, window, cx| { + workspace.open_path((worktree_id, "b.txt"), None, true, window, cx) }) .unwrap() .await @@ -97,10 +104,10 @@ async fn test_host_disconnect( .unwrap(); //TODO: focus - assert!(cx_b.update_view(&editor_b, |editor, cx| editor.is_focused(cx))); - editor_b.update(cx_b, |editor, cx| editor.insert("X", cx)); + assert!(cx_b.update_window_model(&editor_b, |editor, window, _| editor.is_focused(window))); + editor_b.update_in(cx_b, |editor, window, cx| editor.insert("X", window, cx)); - cx_b.update(|cx| { + cx_b.update(|_, cx| { assert!(workspace_b_view.read(cx).is_edited()); }); @@ -120,7 +127,7 @@ async fn test_host_disconnect( // Ensure client B's edited state is reset and that the whole window is blurred. workspace_b - .update(cx_b, |workspace, cx| { + .update(cx_b, |workspace, _, cx| { assert!(workspace.active_modal::(cx).is_some()); assert!(!workspace.is_edited()); }) @@ -128,8 +135,8 @@ async fn test_host_disconnect( // Ensure client B is not prompted to save edits when closing window after disconnecting. let can_close = workspace_b - .update(cx_b, |workspace, cx| { - workspace.prepare_to_close(CloseIntent::Quit, cx) + .update(cx_b, |workspace, window, cx| { + workspace.prepare_to_close(CloseIntent::Quit, window, cx) }) .unwrap() .await @@ -200,11 +207,12 @@ async fn test_newline_above_or_below_does_not_move_guest_cursor( .await .unwrap(); let cx_a = cx_a.add_empty_window(); - let editor_a = cx_a.new_view(|cx| Editor::for_buffer(buffer_a, Some(project_a), cx)); + let editor_a = cx_a + .new_window_model(|window, cx| Editor::for_buffer(buffer_a, Some(project_a), window, cx)); let mut editor_cx_a = EditorTestContext { cx: cx_a.clone(), - window: cx_a.handle(), + window: cx_a.window_handle(), editor: editor_a, assertion_cx: AssertionContextManager::new(), }; @@ -215,11 +223,12 @@ async fn test_newline_above_or_below_does_not_move_guest_cursor( .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)) .await .unwrap(); - let editor_b = cx_b.new_view(|cx| Editor::for_buffer(buffer_b, Some(project_b), cx)); + let editor_b = cx_b + .new_window_model(|window, cx| Editor::for_buffer(buffer_b, Some(project_b), window, cx)); let mut editor_cx_b = EditorTestContext { cx: cx_b.clone(), - window: cx_b.handle(), + window: cx_b.window_handle(), editor: editor_b, assertion_cx: AssertionContextManager::new(), }; @@ -231,8 +240,9 @@ async fn test_newline_above_or_below_does_not_move_guest_cursor( editor_cx_b.set_selections_state(indoc! {" Some textˇ "}); - editor_cx_a - .update_editor(|editor, cx| editor.newline_above(&editor::actions::NewlineAbove, cx)); + editor_cx_a.update_editor(|editor, window, cx| { + editor.newline_above(&editor::actions::NewlineAbove, window, cx) + }); executor.run_until_parked(); editor_cx_a.assert_editor_state(indoc! {" ˇ @@ -252,8 +262,9 @@ async fn test_newline_above_or_below_does_not_move_guest_cursor( Some textˇ "}); - editor_cx_a - .update_editor(|editor, cx| editor.newline_below(&editor::actions::NewlineBelow, cx)); + editor_cx_a.update_editor(|editor, window, cx| { + editor.newline_below(&editor::actions::NewlineBelow, window, cx) + }); executor.run_until_parked(); editor_cx_a.assert_editor_state(indoc! {" @@ -316,8 +327,9 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu .await .unwrap(); let cx_b = cx_b.add_empty_window(); - let editor_b = - cx_b.new_view(|cx| Editor::for_buffer(buffer_b.clone(), Some(project_b.clone()), cx)); + let editor_b = cx_b.new_window_model(|window, cx| { + Editor::for_buffer(buffer_b.clone(), Some(project_b.clone()), window, cx) + }); let fake_language_server = fake_language_servers.next().await.unwrap(); cx_a.background_executor.run_until_parked(); @@ -327,11 +339,11 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu }); // Type a completion trigger character as the guest. - editor_b.update(cx_b, |editor, cx| { - editor.change_selections(None, cx, |s| s.select_ranges([13..13])); - editor.handle_input(".", cx); + editor_b.update_in(cx_b, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| s.select_ranges([13..13])); + editor.handle_input(".", window, cx); }); - cx_b.focus_view(&editor_b); + cx_b.focus(&editor_b); // Receive a completion request as the host's language server. // Return some completions from the host's language server. @@ -393,9 +405,9 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu }); // Confirm a completion on the guest. - editor_b.update(cx_b, |editor, cx| { + editor_b.update_in(cx_b, |editor, window, cx| { assert!(editor.context_menu_visible()); - editor.confirm_completion(&ConfirmCompletion { item_ix: Some(0) }, cx); + editor.confirm_completion(&ConfirmCompletion { item_ix: Some(0) }, window, cx); assert_eq!(editor.text(cx), "fn main() { a.first_method() }"); }); @@ -440,10 +452,10 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu // Now we do a second completion, this time to ensure that documentation/snippets are // resolved - editor_b.update(cx_b, |editor, cx| { - editor.change_selections(None, cx, |s| s.select_ranges([46..46])); - editor.handle_input("; a", cx); - editor.handle_input(".", cx); + editor_b.update_in(cx_b, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| s.select_ranges([46..46])); + editor.handle_input("; a", window, cx); + editor.handle_input(".", window, cx); }); buffer_b.read_with(cx_b, |buffer, _| { @@ -507,18 +519,18 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu completion_response.next().await.unwrap(); - editor_b.update(cx_b, |editor, cx| { + editor_b.update_in(cx_b, |editor, window, cx| { assert!(editor.context_menu_visible()); - editor.context_menu_first(&ContextMenuFirst {}, cx); + editor.context_menu_first(&ContextMenuFirst {}, window, cx); }); resolve_completion_response.next().await.unwrap(); cx_b.executor().run_until_parked(); // When accepting the completion, the snippet is insert. - editor_b.update(cx_b, |editor, cx| { + editor_b.update_in(cx_b, |editor, window, cx| { assert!(editor.context_menu_visible()); - editor.confirm_completion(&ConfirmCompletion { item_ix: Some(0) }, cx); + editor.confirm_completion(&ConfirmCompletion { item_ix: Some(0) }, window, cx); assert_eq!( editor.text(cx), "use d::SomeTrait;\nfn main() { a.first_method(); a.third_method(, , ) }" @@ -568,8 +580,8 @@ async fn test_collaborating_with_code_actions( let project_b = client_b.join_remote_project(project_id, cx_b).await; let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b); let editor_b = workspace_b - .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "main.rs"), None, true, cx) + .update_in(cx_b, |workspace, window, cx| { + workspace.open_path((worktree_id, "main.rs"), None, true, window, cx) }) .await .unwrap() @@ -592,12 +604,12 @@ async fn test_collaborating_with_code_actions( requests.next().await; // Move cursor to a location that contains code actions. - editor_b.update(cx_b, |editor, cx| { - editor.change_selections(None, cx, |s| { + editor_b.update_in(cx_b, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_ranges([Point::new(1, 31)..Point::new(1, 31)]) }); }); - cx_b.focus_view(&editor_b); + cx_b.focus(&editor_b); let mut requests = fake_language_server .handle_request::(|params, _| async move { @@ -657,11 +669,12 @@ async fn test_collaborating_with_code_actions( requests.next().await; // Toggle code actions and wait for them to display. - editor_b.update(cx_b, |editor, cx| { + editor_b.update_in(cx_b, |editor, window, cx| { editor.toggle_code_actions( &ToggleCodeActions { deployed_from_indicator: None, }, + window, cx, ); }); @@ -673,8 +686,8 @@ async fn test_collaborating_with_code_actions( // Confirming the code action will trigger a resolve request. let confirm_action = editor_b - .update(cx_b, |editor, cx| { - Editor::confirm_code_action(editor, &ConfirmCodeAction { item_ix: Some(0) }, cx) + .update_in(cx_b, |editor, window, cx| { + Editor::confirm_code_action(editor, &ConfirmCodeAction { item_ix: Some(0) }, window, cx) }) .unwrap(); fake_language_server.handle_request::( @@ -725,14 +738,14 @@ async fn test_collaborating_with_code_actions( .downcast::() .unwrap() }); - code_action_editor.update(cx_b, |editor, cx| { + code_action_editor.update_in(cx_b, |editor, window, cx| { assert_eq!(editor.text(cx), "mod other;\nfn main() { let foo = 4; }\n"); - editor.undo(&Undo, cx); + editor.undo(&Undo, window, cx); assert_eq!( editor.text(cx), "mod other;\nfn main() { let foo = other::foo(); }\npub fn foo() -> usize { 4 }" ); - editor.redo(&Redo, cx); + editor.redo(&Redo, window, cx); assert_eq!(editor.text(cx), "mod other;\nfn main() { let foo = 4; }\n"); }); } @@ -784,8 +797,8 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b); let editor_b = workspace_b - .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "one.rs"), None, true, cx) + .update_in(cx_b, |workspace, window, cx| { + workspace.open_path((worktree_id, "one.rs"), None, true, window, cx) }) .await .unwrap() @@ -794,9 +807,9 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T let fake_language_server = fake_language_servers.next().await.unwrap(); // Move cursor to a location that can be renamed. - let prepare_rename = editor_b.update(cx_b, |editor, cx| { - editor.change_selections(None, cx, |s| s.select_ranges([7..7])); - editor.rename(&Rename, cx).unwrap() + let prepare_rename = editor_b.update_in(cx_b, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| s.select_ranges([7..7])); + editor.rename(&Rename, window, cx).unwrap() }); fake_language_server @@ -834,12 +847,12 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T }); // Cancel the rename, and repeat the same, but use selections instead of cursor movement - editor_b.update(cx_b, |editor, cx| { - editor.cancel(&editor::actions::Cancel, cx); + editor_b.update_in(cx_b, |editor, window, cx| { + editor.cancel(&editor::actions::Cancel, window, cx); }); - let prepare_rename = editor_b.update(cx_b, |editor, cx| { - editor.change_selections(None, cx, |s| s.select_ranges([7..8])); - editor.rename(&Rename, cx).unwrap() + let prepare_rename = editor_b.update_in(cx_b, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| s.select_ranges([7..8])); + editor.rename(&Rename, window, cx).unwrap() }); fake_language_server @@ -875,8 +888,8 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T }); }); - let confirm_rename = editor_b.update(cx_b, |editor, cx| { - Editor::confirm_rename(editor, &ConfirmRename, cx).unwrap() + let confirm_rename = editor_b.update_in(cx_b, |editor, window, cx| { + Editor::confirm_rename(editor, &ConfirmRename, window, cx).unwrap() }); fake_language_server .handle_request::(|params, _| async move { @@ -934,17 +947,17 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T workspace.active_item_as::(cx).unwrap() }); - rename_editor.update(cx_b, |editor, cx| { + rename_editor.update_in(cx_b, |editor, window, cx| { assert_eq!( editor.text(cx), "const THREE: usize = 1;\nconst TWO: usize = one::THREE + one::THREE;" ); - editor.undo(&Undo, cx); + editor.undo(&Undo, window, cx); assert_eq!( editor.text(cx), "const ONE: usize = 1;\nconst TWO: usize = one::ONE + one::ONE;" ); - editor.redo(&Redo, cx); + editor.redo(&Redo, window, cx); assert_eq!( editor.text(cx), "const THREE: usize = 1;\nconst TWO: usize = one::THREE + one::THREE;" @@ -952,12 +965,12 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T }); // Ensure temporary rename edits cannot be undone/redone. - editor_b.update(cx_b, |editor, cx| { - editor.undo(&Undo, cx); + editor_b.update_in(cx_b, |editor, window, cx| { + editor.undo(&Undo, window, cx); assert_eq!(editor.text(cx), "const ONE: usize = 1;"); - editor.undo(&Undo, cx); + editor.undo(&Undo, window, cx); assert_eq!(editor.text(cx), "const ONE: usize = 1;"); - editor.redo(&Redo, cx); + editor.redo(&Redo, window, cx); assert_eq!(editor.text(cx), "const THREE: usize = 1;"); }) } @@ -1192,7 +1205,8 @@ async fn test_share_project( .await .unwrap(); - let editor_b = cx_b.new_view(|cx| Editor::for_buffer(buffer_b, None, cx)); + let editor_b = + cx_b.new_window_model(|window, cx| Editor::for_buffer(buffer_b, None, window, cx)); // Client A sees client B's selection executor.run_until_parked(); @@ -1206,7 +1220,9 @@ async fn test_share_project( }); // Edit the buffer as client B and see that edit as client A. - editor_b.update(cx_b, |editor, cx| editor.handle_input("ok, ", cx)); + editor_b.update_in(cx_b, |editor, window, cx| { + editor.handle_input("ok, ", window, cx) + }); executor.run_until_parked(); buffer_a.read_with(cx_a, |buffer, _| { @@ -1233,7 +1249,7 @@ async fn test_share_project( let _project_c = client_c.join_remote_project(initial_project.id, cx_c).await; // Client B closes the editor, and client A sees client B's selections removed. - cx_b.update(move |_| drop(editor_b)); + cx_b.update(move |_, _| drop(editor_b)); executor.run_until_parked(); buffer_a.read_with(cx_a, |buffer, _| { @@ -1297,7 +1313,9 @@ async fn test_on_input_format_from_host_to_guest( .await .unwrap(); let cx_a = cx_a.add_empty_window(); - let editor_a = cx_a.new_view(|cx| Editor::for_buffer(buffer_a, Some(project_a.clone()), cx)); + let editor_a = cx_a.new_window_model(|window, cx| { + Editor::for_buffer(buffer_a, Some(project_a.clone()), window, cx) + }); let fake_language_server = fake_language_servers.next().await.unwrap(); executor.run_until_parked(); @@ -1329,10 +1347,10 @@ async fn test_on_input_format_from_host_to_guest( .unwrap(); // Type a on type formatting trigger character as the guest. - cx_a.focus_view(&editor_a); - editor_a.update(cx_a, |editor, cx| { - editor.change_selections(None, cx, |s| s.select_ranges([13..13])); - editor.handle_input(">", cx); + cx_a.focus(&editor_a); + editor_a.update_in(cx_a, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| s.select_ranges([13..13])); + editor.handle_input(">", window, cx); }); executor.run_until_parked(); @@ -1342,9 +1360,9 @@ async fn test_on_input_format_from_host_to_guest( }); // Undo should remove LSP edits first - editor_a.update(cx_a, |editor, cx| { + editor_a.update_in(cx_a, |editor, window, cx| { assert_eq!(editor.text(cx), "fn main() { a>~< }"); - editor.undo(&Undo, cx); + editor.undo(&Undo, window, cx); assert_eq!(editor.text(cx), "fn main() { a> }"); }); executor.run_until_parked(); @@ -1353,9 +1371,9 @@ async fn test_on_input_format_from_host_to_guest( assert_eq!(buffer.text(), "fn main() { a> }") }); - editor_a.update(cx_a, |editor, cx| { + editor_a.update_in(cx_a, |editor, window, cx| { assert_eq!(editor.text(cx), "fn main() { a> }"); - editor.undo(&Undo, cx); + editor.undo(&Undo, window, cx); assert_eq!(editor.text(cx), "fn main() { a }"); }); executor.run_until_parked(); @@ -1417,16 +1435,18 @@ async fn test_on_input_format_from_guest_to_host( .await .unwrap(); let cx_b = cx_b.add_empty_window(); - let editor_b = cx_b.new_view(|cx| Editor::for_buffer(buffer_b, Some(project_b.clone()), cx)); + let editor_b = cx_b.new_window_model(|window, cx| { + Editor::for_buffer(buffer_b, Some(project_b.clone()), window, cx) + }); let fake_language_server = fake_language_servers.next().await.unwrap(); executor.run_until_parked(); // Type a on type formatting trigger character as the guest. - cx_b.focus_view(&editor_b); - editor_b.update(cx_b, |editor, cx| { - editor.change_selections(None, cx, |s| s.select_ranges([13..13])); - editor.handle_input(":", cx); + cx_b.focus(&editor_b); + editor_b.update_in(cx_b, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| s.select_ranges([13..13])); + editor.handle_input(":", window, cx); }); // Receive an OnTypeFormatting request as the host's language server. @@ -1465,9 +1485,9 @@ async fn test_on_input_format_from_guest_to_host( }); // Undo should remove LSP edits first - editor_b.update(cx_b, |editor, cx| { + editor_b.update_in(cx_b, |editor, window, cx| { assert_eq!(editor.text(cx), "fn main() { a:~: }"); - editor.undo(&Undo, cx); + editor.undo(&Undo, window, cx); assert_eq!(editor.text(cx), "fn main() { a: }"); }); executor.run_until_parked(); @@ -1476,9 +1496,9 @@ async fn test_on_input_format_from_guest_to_host( assert_eq!(buffer.text(), "fn main() { a: }") }); - editor_b.update(cx_b, |editor, cx| { + editor_b.update_in(cx_b, |editor, window, cx| { assert_eq!(editor.text(cx), "fn main() { a: }"); - editor.undo(&Undo, cx); + editor.undo(&Undo, window, cx); assert_eq!(editor.text(cx), "fn main() { a }"); }); executor.run_until_parked(); @@ -1589,8 +1609,8 @@ async fn test_mutual_editor_inlay_hint_cache_update( .await .unwrap(); let editor_a = workspace_a - .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, "main.rs"), None, true, cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.open_path((worktree_id, "main.rs"), None, true, window, cx) }) .await .unwrap() @@ -1639,8 +1659,8 @@ async fn test_mutual_editor_inlay_hint_cache_update( }); let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b); let editor_b = workspace_b - .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "main.rs"), None, true, cx) + .update_in(cx_b, |workspace, window, cx| { + workspace.open_path((worktree_id, "main.rs"), None, true, window, cx) }) .await .unwrap() @@ -1657,11 +1677,11 @@ async fn test_mutual_editor_inlay_hint_cache_update( }); let after_client_edit = edits_made.fetch_add(1, atomic::Ordering::Release) + 1; - editor_b.update(cx_b, |editor, cx| { - editor.change_selections(None, cx, |s| s.select_ranges([13..13].clone())); - editor.handle_input(":", cx); + editor_b.update_in(cx_b, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| s.select_ranges([13..13].clone())); + editor.handle_input(":", window, cx); }); - cx_b.focus_view(&editor_b); + cx_b.focus(&editor_b); executor.run_until_parked(); editor_a.update(cx_a, |editor, _| { @@ -1678,11 +1698,11 @@ async fn test_mutual_editor_inlay_hint_cache_update( }); let after_host_edit = edits_made.fetch_add(1, atomic::Ordering::Release) + 1; - editor_a.update(cx_a, |editor, cx| { - editor.change_selections(None, cx, |s| s.select_ranges([13..13])); - editor.handle_input("a change to increment both buffers' versions", cx); + editor_a.update_in(cx_a, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| s.select_ranges([13..13])); + editor.handle_input("a change to increment both buffers' versions", window, cx); }); - cx_a.focus_view(&editor_a); + cx_a.focus(&editor_a); executor.run_until_parked(); editor_a.update(cx_a, |editor, _| { @@ -1815,8 +1835,8 @@ async fn test_inlay_hint_refresh_is_forwarded( cx_a.background_executor.start_waiting(); let editor_a = workspace_a - .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, "main.rs"), None, true, cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.open_path((worktree_id, "main.rs"), None, true, window, cx) }) .await .unwrap() @@ -1824,8 +1844,8 @@ async fn test_inlay_hint_refresh_is_forwarded( .unwrap(); let editor_b = workspace_b - .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "main.rs"), None, true, cx) + .update_in(cx_b, |workspace, window, cx| { + workspace.open_path((worktree_id, "main.rs"), None, true, window, cx) }) .await .unwrap() @@ -1985,8 +2005,8 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA // Create editor_a let (workspace_a, cx_a) = client_a.build_workspace(&project_a, cx_a); let editor_a = workspace_a - .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, "file.txt"), None, true, cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.open_path((worktree_id, "file.txt"), None, true, window, cx) }) .await .unwrap() @@ -1997,8 +2017,8 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA let project_b = client_b.join_remote_project(project_id, cx_b).await; let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b); let editor_b = workspace_b - .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "file.txt"), None, true, cx) + .update_in(cx_b, |workspace, window, cx| { + workspace.open_path((worktree_id, "file.txt"), None, true, window, cx) }) .await .unwrap() @@ -2006,9 +2026,9 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA .unwrap(); // client_b now requests git blame for the open buffer - editor_b.update(cx_b, |editor_b, cx| { + editor_b.update_in(cx_b, |editor_b, window, cx| { assert!(editor_b.blame().is_none()); - editor_b.toggle_git_blame(&editor::actions::ToggleGitBlame {}, cx); + editor_b.toggle_git_blame(&editor::actions::ToggleGitBlame {}, window, cx); }); cx_a.executor().run_until_parked(); @@ -2054,7 +2074,7 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA // editor_b updates the file, which gets sent to client_a, which updates git blame, // which gets back to client_b. - editor_b.update(cx_b, |editor_b, cx| { + editor_b.update_in(cx_b, |editor_b, _, cx| { editor_b.edit([(Point::new(0, 3)..Point::new(0, 3), "FOO")], cx); }); @@ -2089,7 +2109,7 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA }); // Now editor_a also updates the file - editor_a.update(cx_a, |editor_a, cx| { + editor_a.update_in(cx_a, |editor_a, _, cx| { editor_a.edit([(Point::new(1, 3)..Point::new(1, 3), "FOO")], cx); }); @@ -2175,19 +2195,21 @@ async fn test_collaborating_with_editorconfig( .await .unwrap(); let cx_a = cx_a.add_empty_window(); - let main_editor_a = - cx_a.new_view(|cx| Editor::for_buffer(main_buffer_a, Some(project_a.clone()), cx)); - let other_editor_a = - cx_a.new_view(|cx| Editor::for_buffer(other_buffer_a, Some(project_a), cx)); + let main_editor_a = cx_a.new_window_model(|window, cx| { + Editor::for_buffer(main_buffer_a, Some(project_a.clone()), window, cx) + }); + let other_editor_a = cx_a.new_window_model(|window, cx| { + Editor::for_buffer(other_buffer_a, Some(project_a), window, cx) + }); let mut main_editor_cx_a = EditorTestContext { cx: cx_a.clone(), - window: cx_a.handle(), + window: cx_a.window_handle(), editor: main_editor_a, assertion_cx: AssertionContextManager::new(), }; let mut other_editor_cx_a = EditorTestContext { cx: cx_a.clone(), - window: cx_a.handle(), + window: cx_a.window_handle(), editor: other_editor_a, assertion_cx: AssertionContextManager::new(), }; @@ -2207,19 +2229,21 @@ async fn test_collaborating_with_editorconfig( .await .unwrap(); let cx_b = cx_b.add_empty_window(); - let main_editor_b = - cx_b.new_view(|cx| Editor::for_buffer(main_buffer_b, Some(project_b.clone()), cx)); - let other_editor_b = - cx_b.new_view(|cx| Editor::for_buffer(other_buffer_b, Some(project_b.clone()), cx)); + let main_editor_b = cx_b.new_window_model(|window, cx| { + Editor::for_buffer(main_buffer_b, Some(project_b.clone()), window, cx) + }); + let other_editor_b = cx_b.new_window_model(|window, cx| { + Editor::for_buffer(other_buffer_b, Some(project_b.clone()), window, cx) + }); let mut main_editor_cx_b = EditorTestContext { cx: cx_b.clone(), - window: cx_b.handle(), + window: cx_b.window_handle(), editor: main_editor_b, assertion_cx: AssertionContextManager::new(), }; let mut other_editor_cx_b = EditorTestContext { cx: cx_b.clone(), - window: cx_b.handle(), + window: cx_b.window_handle(), editor: other_editor_b, assertion_cx: AssertionContextManager::new(), }; @@ -2383,12 +2407,12 @@ fn tab_undo_assert( cx_b.assert_editor_state(expected_initial); if a_tabs { - cx_a.update_editor(|editor, cx| { - editor.tab(&editor::actions::Tab, cx); + cx_a.update_editor(|editor, window, cx| { + editor.tab(&editor::actions::Tab, window, cx); }); } else { - cx_b.update_editor(|editor, cx| { - editor.tab(&editor::actions::Tab, cx); + cx_b.update_editor(|editor, window, cx| { + editor.tab(&editor::actions::Tab, window, cx); }); } @@ -2399,12 +2423,12 @@ fn tab_undo_assert( cx_b.assert_editor_state(expected_tabbed); if a_tabs { - cx_a.update_editor(|editor, cx| { - editor.undo(&editor::actions::Undo, cx); + cx_a.update_editor(|editor, window, cx| { + editor.undo(&editor::actions::Undo, window, cx); }); } else { - cx_b.update_editor(|editor, cx| { - editor.undo(&editor::actions::Undo, cx); + cx_b.update_editor(|editor, window, cx| { + editor.undo(&editor::actions::Undo, window, cx); }); } cx_a.run_until_parked(); diff --git a/crates/collab/src/tests/following_tests.rs b/crates/collab/src/tests/following_tests.rs index 4de368d2ea..58aed662b2 100644 --- a/crates/collab/src/tests/following_tests.rs +++ b/crates/collab/src/tests/following_tests.rs @@ -8,8 +8,8 @@ use collab_ui::{ }; use editor::{Editor, ExcerptRange, MultiBuffer}; use gpui::{ - point, BackgroundExecutor, BorrowAppContext, Context, Entity, SharedString, TestAppContext, - View, VisualContext, VisualTestContext, + point, AppContext as _, BackgroundExecutor, BorrowAppContext, Entity, SharedString, + TestAppContext, VisualTestContext, }; use language::Capability; use project::WorktreeSettings; @@ -77,23 +77,23 @@ async fn test_basic_following( let (workspace_a, cx_a) = client_a.build_workspace(&project_a, cx_a); let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b); - cx_b.update(|cx| { - assert!(cx.is_window_active()); + cx_b.update(|window, _| { + assert!(window.is_window_active()); }); // Client A opens some editors. let pane_a = workspace_a.update(cx_a, |workspace, _| workspace.active_pane().clone()); let editor_a1 = workspace_a - .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, "1.txt"), None, true, cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.open_path((worktree_id, "1.txt"), None, true, window, cx) }) .await .unwrap() .downcast::() .unwrap(); let editor_a2 = workspace_a - .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, "2.txt"), None, true, cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.open_path((worktree_id, "2.txt"), None, true, window, cx) }) .await .unwrap() @@ -102,8 +102,8 @@ async fn test_basic_following( // Client B opens an editor. let editor_b1 = workspace_b - .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "1.txt"), None, true, cx) + .update_in(cx_b, |workspace, window, cx| { + workspace.open_path((worktree_id, "1.txt"), None, true, window, cx) }) .await .unwrap() @@ -116,22 +116,24 @@ async fn test_basic_following( let peer_id_d = client_d.peer_id().unwrap(); // Client A updates their selections in those editors - editor_a1.update(cx_a, |editor, cx| { - editor.handle_input("a", cx); - editor.handle_input("b", cx); - editor.handle_input("c", cx); - editor.select_left(&Default::default(), cx); + editor_a1.update_in(cx_a, |editor, window, cx| { + editor.handle_input("a", window, cx); + editor.handle_input("b", window, cx); + editor.handle_input("c", window, cx); + editor.select_left(&Default::default(), window, cx); assert_eq!(editor.selections.ranges(cx), vec![3..2]); }); - editor_a2.update(cx_a, |editor, cx| { - editor.handle_input("d", cx); - editor.handle_input("e", cx); - editor.select_left(&Default::default(), cx); + editor_a2.update_in(cx_a, |editor, window, cx| { + editor.handle_input("d", window, cx); + editor.handle_input("e", window, cx); + editor.select_left(&Default::default(), window, cx); assert_eq!(editor.selections.ranges(cx), vec![2..1]); }); // When client B starts following client A, only the active view state is replicated to client B. - workspace_b.update(cx_b, |workspace, cx| workspace.follow(peer_id_a, cx)); + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.follow(peer_id_a, window, cx) + }); cx_c.executor().run_until_parked(); let editor_b2 = workspace_b.update(cx_b, |workspace, cx| { @@ -165,7 +167,9 @@ async fn test_basic_following( drop(project_c); // Client C also follows client A. - workspace_c.update(cx_c, |workspace, cx| workspace.follow(peer_id_a, cx)); + workspace_c.update_in(cx_c, |workspace, window, cx| { + workspace.follow(peer_id_a, window, cx) + }); cx_d.executor().run_until_parked(); let active_call_d = cx_d.read(ActiveCall::global); @@ -188,8 +192,8 @@ async fn test_basic_following( } // Client C unfollows client A. - workspace_c.update(cx_c, |workspace, cx| { - workspace.unfollow(peer_id_a, cx).unwrap(); + workspace_c.update_in(cx_c, |workspace, window, cx| { + workspace.unfollow(peer_id_a, window, cx).unwrap(); }); // All clients see that clients B is following client A. @@ -203,7 +207,9 @@ async fn test_basic_following( } // Client C re-follows client A. - workspace_c.update(cx_c, |workspace, cx| workspace.follow(peer_id_a, cx)); + workspace_c.update_in(cx_c, |workspace, window, cx| { + workspace.follow(peer_id_a, window, cx) + }); // All clients see that clients B and C are following client A. cx_c.executor().run_until_parked(); @@ -216,9 +222,13 @@ async fn test_basic_following( } // Client D follows client B, then switches to following client C. - workspace_d.update(cx_d, |workspace, cx| workspace.follow(peer_id_b, cx)); + workspace_d.update_in(cx_d, |workspace, window, cx| { + workspace.follow(peer_id_b, window, cx) + }); cx_a.executor().run_until_parked(); - workspace_d.update(cx_d, |workspace, cx| workspace.follow(peer_id_c, cx)); + workspace_d.update_in(cx_d, |workspace, window, cx| { + workspace.follow(peer_id_c, window, cx) + }); // All clients see that D is following C cx_a.executor().run_until_parked(); @@ -235,8 +245,8 @@ async fn test_basic_following( // Client C closes the project. let weak_workspace_c = workspace_c.downgrade(); - workspace_c.update(cx_c, |workspace, cx| { - workspace.close_window(&Default::default(), cx); + workspace_c.update_in(cx_c, |workspace, window, cx| { + workspace.close_window(&Default::default(), window, cx); }); executor.run_until_parked(); // are you sure you want to leave the call? @@ -260,8 +270,8 @@ async fn test_basic_following( } // When client A activates a different editor, client B does so as well. - workspace_a.update(cx_a, |workspace, cx| { - workspace.activate_item(&editor_a1, true, true, cx) + workspace_a.update_in(cx_a, |workspace, window, cx| { + workspace.activate_item(&editor_a1, true, true, window, cx) }); executor.run_until_parked(); workspace_b.update(cx_b, |workspace, cx| { @@ -272,7 +282,7 @@ async fn test_basic_following( }); // When client A opens a multibuffer, client B does so as well. - let multibuffer_a = cx_a.new_model(|cx| { + let multibuffer_a = cx_a.new(|cx| { let buffer_a1 = project_a.update(cx, |project, cx| { project .get_open_buffer(&(worktree_id, "1.txt").into(), cx) @@ -302,11 +312,11 @@ async fn test_basic_following( ); result }); - let multibuffer_editor_a = workspace_a.update(cx_a, |workspace, cx| { - let editor = cx.new_view(|cx| { - Editor::for_multibuffer(multibuffer_a, Some(project_a.clone()), true, cx) + let multibuffer_editor_a = workspace_a.update_in(cx_a, |workspace, window, cx| { + let editor = cx.new(|cx| { + Editor::for_multibuffer(multibuffer_a, Some(project_a.clone()), true, window, cx) }); - workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, cx); + workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx); editor }); executor.run_until_parked(); @@ -324,8 +334,8 @@ async fn test_basic_following( // When client A navigates back and forth, client B does so as well. workspace_a - .update(cx_a, |workspace, cx| { - workspace.go_back(workspace.active_pane().downgrade(), cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.go_back(workspace.active_pane().downgrade(), window, cx) }) .await .unwrap(); @@ -338,8 +348,8 @@ async fn test_basic_following( }); workspace_a - .update(cx_a, |workspace, cx| { - workspace.go_back(workspace.active_pane().downgrade(), cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.go_back(workspace.active_pane().downgrade(), window, cx) }) .await .unwrap(); @@ -352,8 +362,8 @@ async fn test_basic_following( }); workspace_a - .update(cx_a, |workspace, cx| { - workspace.go_forward(workspace.active_pane().downgrade(), cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.go_forward(workspace.active_pane().downgrade(), window, cx) }) .await .unwrap(); @@ -366,8 +376,8 @@ async fn test_basic_following( }); // Changes to client A's editor are reflected on client B. - editor_a1.update(cx_a, |editor, cx| { - editor.change_selections(None, cx, |s| s.select_ranges([1..1, 2..2])); + editor_a1.update_in(cx_a, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| s.select_ranges([1..1, 2..2])); }); executor.advance_clock(workspace::item::LEADER_UPDATE_THROTTLE); executor.run_until_parked(); @@ -377,13 +387,15 @@ async fn test_basic_following( assert_eq!(editor.selections.ranges(cx), &[1..1, 2..2]); }); - editor_a1.update(cx_a, |editor, cx| editor.set_text("TWO", cx)); + editor_a1.update_in(cx_a, |editor, window, cx| { + editor.set_text("TWO", window, cx) + }); executor.run_until_parked(); editor_b1.update(cx_b, |editor, cx| assert_eq!(editor.text(cx), "TWO")); - editor_a1.update(cx_a, |editor, cx| { - editor.change_selections(None, cx, |s| s.select_ranges([3..3])); - editor.set_scroll_position(point(0., 100.), cx); + editor_a1.update_in(cx_a, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| s.select_ranges([3..3])); + editor.set_scroll_position(point(0., 100.), window, cx); }); executor.advance_clock(workspace::item::LEADER_UPDATE_THROTTLE); executor.run_until_parked(); @@ -392,11 +404,11 @@ async fn test_basic_following( }); // After unfollowing, client B stops receiving updates from client A. - workspace_b.update(cx_b, |workspace, cx| { - workspace.unfollow(peer_id_a, cx).unwrap() + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.unfollow(peer_id_a, window, cx).unwrap() }); - workspace_a.update(cx_a, |workspace, cx| { - workspace.activate_item(&editor_a2, true, true, cx) + workspace_a.update_in(cx_a, |workspace, window, cx| { + workspace.activate_item(&editor_a2, true, true, window, cx) }); executor.run_until_parked(); assert_eq!( @@ -408,14 +420,16 @@ async fn test_basic_following( ); // Client A starts following client B. - workspace_a.update(cx_a, |workspace, cx| workspace.follow(peer_id_b, cx)); + workspace_a.update_in(cx_a, |workspace, window, cx| { + workspace.follow(peer_id_b, window, cx) + }); executor.run_until_parked(); assert_eq!( workspace_a.update(cx_a, |workspace, _| workspace.leader_for_pane(&pane_a)), Some(peer_id_b) ); assert_eq!( - workspace_a.update(cx_a, |workspace, cx| workspace + workspace_a.update_in(cx_a, |workspace, _, cx| workspace .active_item(cx) .unwrap() .item_id()), @@ -471,8 +485,8 @@ async fn test_basic_following( }); // Client B activates a multibuffer that was created by following client A. Client A returns to that multibuffer. - workspace_b.update(cx_b, |workspace, cx| { - workspace.activate_item(&multibuffer_editor_b, true, true, cx) + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.activate_item(&multibuffer_editor_b, true, true, window, cx) }); executor.run_until_parked(); workspace_a.update(cx_a, |workspace, cx| { @@ -483,10 +497,10 @@ async fn test_basic_following( }); // Client B activates a panel, and the previously-opened screen-sharing item gets activated. - let panel = cx_b.new_view(|cx| TestPanel::new(DockPosition::Left, cx)); - workspace_b.update(cx_b, |workspace, cx| { - workspace.add_panel(panel, cx); - workspace.toggle_panel_focus::(cx); + let panel = cx_b.new(|cx| TestPanel::new(DockPosition::Left, cx)); + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.add_panel(panel, window, cx); + workspace.toggle_panel_focus::(window, cx); }); executor.run_until_parked(); assert_eq!( @@ -498,8 +512,8 @@ async fn test_basic_following( ); // Toggling the focus back to the pane causes client A to return to the multibuffer. - workspace_b.update(cx_b, |workspace, cx| { - workspace.toggle_panel_focus::(cx); + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.toggle_panel_focus::(window, cx); }); executor.run_until_parked(); workspace_a.update(cx_a, |workspace, cx| { @@ -511,10 +525,10 @@ async fn test_basic_following( // Client B activates an item that doesn't implement following, // so the previously-opened screen-sharing item gets activated. - let unfollowable_item = cx_b.new_view(TestItem::new); - workspace_b.update(cx_b, |workspace, cx| { + let unfollowable_item = cx_b.new(TestItem::new); + workspace_b.update_in(cx_b, |workspace, window, cx| { workspace.active_pane().update(cx, |pane, cx| { - pane.add_item(Box::new(unfollowable_item), true, true, None, cx) + pane.add_item(Box::new(unfollowable_item), true, true, None, window, cx) }) }); executor.run_until_parked(); @@ -593,19 +607,19 @@ async fn test_following_tab_order( //Open 1, 3 in that order on client A workspace_a - .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, "1.txt"), None, true, cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.open_path((worktree_id, "1.txt"), None, true, window, cx) }) .await .unwrap(); workspace_a - .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, "3.txt"), None, true, cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.open_path((worktree_id, "3.txt"), None, true, window, cx) }) .await .unwrap(); - let pane_paths = |pane: &View, cx: &mut VisualTestContext| { + let pane_paths = |pane: &Entity, cx: &mut VisualTestContext| { pane.update(cx, |pane, cx| { pane.items() .map(|item| { @@ -624,13 +638,15 @@ async fn test_following_tab_order( assert_eq!(&pane_paths(&pane_a, cx_a), &["1.txt", "3.txt"]); //Follow client B as client A - workspace_a.update(cx_a, |workspace, cx| workspace.follow(client_b_id, cx)); + workspace_a.update_in(cx_a, |workspace, window, cx| { + workspace.follow(client_b_id, window, cx) + }); executor.run_until_parked(); //Open just 2 on client B workspace_b - .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "2.txt"), None, true, cx) + .update_in(cx_b, |workspace, window, cx| { + workspace.open_path((worktree_id, "2.txt"), None, true, window, cx) }) .await .unwrap(); @@ -641,8 +657,8 @@ async fn test_following_tab_order( //Open just 1 on client B workspace_b - .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "1.txt"), None, true, cx) + .update_in(cx_b, |workspace, window, cx| { + workspace.open_path((worktree_id, "1.txt"), None, true, window, cx) }) .await .unwrap(); @@ -701,8 +717,8 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T // Client A opens a file. let (workspace_a, cx_a) = client_a.build_workspace(&project_a, cx_a); workspace_a - .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, "1.txt"), None, true, cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.open_path((worktree_id, "1.txt"), None, true, window, cx) }) .await .unwrap() @@ -712,8 +728,8 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T // Client B opens a different file. let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b); workspace_b - .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "2.txt"), None, true, cx) + .update_in(cx_b, |workspace, window, cx| { + workspace.open_path((worktree_id, "2.txt"), None, true, window, cx) }) .await .unwrap() @@ -721,24 +737,38 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T .unwrap(); // Clients A and B follow each other in split panes - workspace_a.update(cx_a, |workspace, cx| { - workspace.split_and_clone(workspace.active_pane().clone(), SplitDirection::Right, cx); + workspace_a.update_in(cx_a, |workspace, window, cx| { + workspace.split_and_clone( + workspace.active_pane().clone(), + SplitDirection::Right, + window, + cx, + ); }); - workspace_a.update(cx_a, |workspace, cx| { - workspace.follow(client_b.peer_id().unwrap(), cx) + workspace_a.update_in(cx_a, |workspace, window, cx| { + workspace.follow(client_b.peer_id().unwrap(), window, cx) }); executor.run_until_parked(); - workspace_b.update(cx_b, |workspace, cx| { - workspace.split_and_clone(workspace.active_pane().clone(), SplitDirection::Right, cx); + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.split_and_clone( + workspace.active_pane().clone(), + SplitDirection::Right, + window, + cx, + ); }); - workspace_b.update(cx_b, |workspace, cx| { - workspace.follow(client_a.peer_id().unwrap(), cx) + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.follow(client_a.peer_id().unwrap(), window, cx) }); executor.run_until_parked(); // Clients A and B return focus to the original files they had open - workspace_a.update(cx_a, |workspace, cx| workspace.activate_next_pane(cx)); - workspace_b.update(cx_b, |workspace, cx| workspace.activate_next_pane(cx)); + workspace_a.update_in(cx_a, |workspace, window, cx| { + workspace.activate_next_pane(window, cx) + }); + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.activate_next_pane(window, cx) + }); executor.run_until_parked(); // Both clients see the other client's focused file in their right pane. @@ -775,15 +805,15 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T // Clients A and B each open a new file. workspace_a - .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, "3.txt"), None, true, cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.open_path((worktree_id, "3.txt"), None, true, window, cx) }) .await .unwrap(); workspace_b - .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "4.txt"), None, true, cx) + .update_in(cx_b, |workspace, window, cx| { + workspace.open_path((worktree_id, "4.txt"), None, true, window, cx) }) .await .unwrap(); @@ -831,7 +861,9 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T ); // Client A focuses their right pane, in which they're following client B. - workspace_a.update(cx_a, |workspace, cx| workspace.activate_next_pane(cx)); + workspace_a.update_in(cx_a, |workspace, window, cx| { + workspace.activate_next_pane(window, cx) + }); executor.run_until_parked(); // Client B sees that client A is now looking at the same file as them. @@ -877,7 +909,9 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T // Client B focuses their right pane, in which they're following client A, // who is following them. - workspace_b.update(cx_b, |workspace, cx| workspace.activate_next_pane(cx)); + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.activate_next_pane(window, cx) + }); executor.run_until_parked(); // Client A sees that client B is now looking at the same file as them. @@ -923,9 +957,9 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T // Client B focuses a file that they previously followed A to, breaking // the follow. - workspace_b.update(cx_b, |workspace, cx| { + workspace_b.update_in(cx_b, |workspace, window, cx| { workspace.active_pane().update(cx, |pane, cx| { - pane.activate_prev_item(true, cx); + pane.activate_prev_item(true, window, cx); }); }); executor.run_until_parked(); @@ -974,9 +1008,9 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T // Client B closes tabs, some of which were originally opened by client A, // and some of which were originally opened by client B. - workspace_b.update(cx_b, |workspace, cx| { + workspace_b.update_in(cx_b, |workspace, window, cx| { workspace.active_pane().update(cx, |pane, cx| { - pane.close_inactive_items(&Default::default(), cx) + pane.close_inactive_items(&Default::default(), window, cx) .unwrap() .detach(); }); @@ -1022,14 +1056,14 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T ); // Client B follows client A again. - workspace_b.update(cx_b, |workspace, cx| { - workspace.follow(client_a.peer_id().unwrap(), cx) + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.follow(client_a.peer_id().unwrap(), window, cx) }); executor.run_until_parked(); // Client A cycles through some tabs. - workspace_a.update(cx_a, |workspace, cx| { + workspace_a.update_in(cx_a, |workspace, window, cx| { workspace.active_pane().update(cx, |pane, cx| { - pane.activate_prev_item(true, cx); + pane.activate_prev_item(true, window, cx); }); }); executor.run_until_parked(); @@ -1071,9 +1105,9 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T ] ); - workspace_a.update(cx_a, |workspace, cx| { + workspace_a.update_in(cx_a, |workspace, window, cx| { workspace.active_pane().update(cx, |pane, cx| { - pane.activate_prev_item(true, cx); + pane.activate_prev_item(true, window, cx); }); }); executor.run_until_parked(); @@ -1118,9 +1152,9 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T ] ); - workspace_a.update(cx_a, |workspace, cx| { + workspace_a.update_in(cx_a, |workspace, window, cx| { workspace.active_pane().update(cx, |pane, cx| { - pane.activate_prev_item(true, cx); + pane.activate_prev_item(true, window, cx); }); }); executor.run_until_parked(); @@ -1215,8 +1249,8 @@ async fn test_auto_unfollowing(cx_a: &mut TestAppContext, cx_b: &mut TestAppCont let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b); let _editor_a1 = workspace_a - .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, "1.txt"), None, true, cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.open_path((worktree_id, "1.txt"), None, true, window, cx) }) .await .unwrap() @@ -1228,7 +1262,9 @@ async fn test_auto_unfollowing(cx_a: &mut TestAppContext, cx_b: &mut TestAppCont let leader_id = project_b.update(cx_b, |project, _| { project.collaborators().values().next().unwrap().peer_id }); - workspace_b.update(cx_b, |workspace, cx| workspace.follow(leader_id, cx)); + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.follow(leader_id, window, cx) + }); executor.run_until_parked(); assert_eq!( workspace_b.update(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)), @@ -1243,15 +1279,17 @@ async fn test_auto_unfollowing(cx_a: &mut TestAppContext, cx_b: &mut TestAppCont }); // When client B moves, it automatically stops following client A. - editor_b2.update(cx_b, |editor, cx| { - editor.move_right(&editor::actions::MoveRight, cx) + editor_b2.update_in(cx_b, |editor, window, cx| { + editor.move_right(&editor::actions::MoveRight, window, cx) }); assert_eq!( workspace_b.update(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)), None ); - workspace_b.update(cx_b, |workspace, cx| workspace.follow(leader_id, cx)); + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.follow(leader_id, window, cx) + }); executor.run_until_parked(); assert_eq!( workspace_b.update(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)), @@ -1259,13 +1297,15 @@ async fn test_auto_unfollowing(cx_a: &mut TestAppContext, cx_b: &mut TestAppCont ); // When client B edits, it automatically stops following client A. - editor_b2.update(cx_b, |editor, cx| editor.insert("X", cx)); + editor_b2.update_in(cx_b, |editor, window, cx| editor.insert("X", window, cx)); assert_eq!( - workspace_b.update(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)), + workspace_b.update_in(cx_b, |workspace, _, _| workspace.leader_for_pane(&pane_b)), None ); - workspace_b.update(cx_b, |workspace, cx| workspace.follow(leader_id, cx)); + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.follow(leader_id, window, cx) + }); executor.run_until_parked(); assert_eq!( workspace_b.update(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)), @@ -1273,15 +1313,17 @@ async fn test_auto_unfollowing(cx_a: &mut TestAppContext, cx_b: &mut TestAppCont ); // When client B scrolls, it automatically stops following client A. - editor_b2.update(cx_b, |editor, cx| { - editor.set_scroll_position(point(0., 3.), cx) + editor_b2.update_in(cx_b, |editor, window, cx| { + editor.set_scroll_position(point(0., 3.), window, cx) }); assert_eq!( workspace_b.update(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)), None ); - workspace_b.update(cx_b, |workspace, cx| workspace.follow(leader_id, cx)); + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.follow(leader_id, window, cx) + }); executor.run_until_parked(); assert_eq!( workspace_b.update(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)), @@ -1289,15 +1331,17 @@ async fn test_auto_unfollowing(cx_a: &mut TestAppContext, cx_b: &mut TestAppCont ); // When client B activates a different pane, it continues following client A in the original pane. - workspace_b.update(cx_b, |workspace, cx| { - workspace.split_and_clone(pane_b.clone(), SplitDirection::Right, cx) + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.split_and_clone(pane_b.clone(), SplitDirection::Right, window, cx) }); assert_eq!( workspace_b.update(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)), Some(leader_id) ); - workspace_b.update(cx_b, |workspace, cx| workspace.activate_next_pane(cx)); + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.activate_next_pane(window, cx) + }); assert_eq!( workspace_b.update(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)), Some(leader_id) @@ -1305,8 +1349,8 @@ async fn test_auto_unfollowing(cx_a: &mut TestAppContext, cx_b: &mut TestAppCont // When client B activates a different item in the original pane, it automatically stops following client A. workspace_b - .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "2.txt"), None, true, cx) + .update_in(cx_b, |workspace, window, cx| { + workspace.open_path((worktree_id, "2.txt"), None, true, window, cx) }) .await .unwrap(); @@ -1352,8 +1396,12 @@ async fn test_peers_simultaneously_following_each_other( project.collaborators().values().next().unwrap().peer_id }); - workspace_a.update(cx_a, |workspace, cx| workspace.follow(client_b_id, cx)); - workspace_b.update(cx_b, |workspace, cx| workspace.follow(client_a_id, cx)); + workspace_a.update_in(cx_a, |workspace, window, cx| { + workspace.follow(client_b_id, window, cx) + }); + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.follow(client_a_id, window, cx) + }); executor.run_until_parked(); workspace_a.update(cx_a, |workspace, _| { @@ -1434,8 +1482,8 @@ async fn test_following_across_workspaces(cx_a: &mut TestAppContext, cx_b: &mut .unwrap(); workspace_a - .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id_a, "w.rs"), None, true, cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.open_path((worktree_id_a, "w.rs"), None, true, window, cx) }) .await .unwrap(); @@ -1443,8 +1491,8 @@ async fn test_following_across_workspaces(cx_a: &mut TestAppContext, cx_b: &mut executor.run_until_parked(); assert_eq!(visible_push_notifications(cx_b).len(), 1); - workspace_b.update(cx_b, |workspace, cx| { - workspace.follow(client_a.peer_id().unwrap(), cx) + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.follow(client_a.peer_id().unwrap(), window, cx) }); executor.run_until_parked(); @@ -1490,8 +1538,8 @@ async fn test_following_across_workspaces(cx_a: &mut TestAppContext, cx_b: &mut // b moves to x.rs in a's project, and a follows workspace_b_project_a - .update(&mut cx_b2, |workspace, cx| { - workspace.open_path((worktree_id_a, "x.rs"), None, true, cx) + .update_in(&mut cx_b2, |workspace, window, cx| { + workspace.open_path((worktree_id_a, "x.rs"), None, true, window, cx) }) .await .unwrap(); @@ -1505,8 +1553,8 @@ async fn test_following_across_workspaces(cx_a: &mut TestAppContext, cx_b: &mut ); }); - workspace_a.update(cx_a, |workspace, cx| { - workspace.follow(client_b.peer_id().unwrap(), cx) + workspace_a.update_in(cx_a, |workspace, window, cx| { + workspace.follow(client_b.peer_id().unwrap(), window, cx) }); executor.run_until_parked(); @@ -1522,8 +1570,8 @@ async fn test_following_across_workspaces(cx_a: &mut TestAppContext, cx_b: &mut // b moves to y.rs in b's project, a is still following but can't yet see workspace_b - .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id_b, "y.rs"), None, true, cx) + .update_in(cx_b, |workspace, window, cx| { + workspace.open_path((worktree_id_b, "y.rs"), None, true, window, cx) }) .await .unwrap(); @@ -1544,7 +1592,7 @@ async fn test_following_across_workspaces(cx_a: &mut TestAppContext, cx_b: &mut executor.run_until_parked(); assert_eq!(visible_push_notifications(cx_a).len(), 1); - cx_a.update(|cx| { + cx_a.update(|_, cx| { workspace::join_in_room_project( project_b_id, client_b.user_id().unwrap(), @@ -1607,8 +1655,8 @@ async fn test_following_stops_on_unshare(cx_a: &mut TestAppContext, cx_b: &mut T }); // b should follow a to position 1 - editor_a.update(cx_a, |editor, cx| { - editor.change_selections(None, cx, |s| s.select_ranges([1..1])) + editor_a.update_in(cx_a, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| s.select_ranges([1..1])) }); cx_a.executor() .advance_clock(workspace::item::LEADER_UPDATE_THROTTLE); @@ -1618,7 +1666,7 @@ async fn test_following_stops_on_unshare(cx_a: &mut TestAppContext, cx_b: &mut T }); // a unshares the project - cx_a.update(|cx| { + cx_a.update(|_, cx| { let project = workspace_a.read(cx).project().clone(); ActiveCall::global(cx).update(cx, |call, cx| { call.unshare_project(project, cx).unwrap(); @@ -1627,8 +1675,8 @@ async fn test_following_stops_on_unshare(cx_a: &mut TestAppContext, cx_b: &mut T cx_a.run_until_parked(); // b should not follow a to position 2 - editor_a.update(cx_a, |editor, cx| { - editor.change_selections(None, cx, |s| s.select_ranges([2..2])) + editor_a.update_in(cx_a, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| s.select_ranges([2..2])) }); cx_a.executor() .advance_clock(workspace::item::LEADER_UPDATE_THROTTLE); @@ -1636,7 +1684,7 @@ async fn test_following_stops_on_unshare(cx_a: &mut TestAppContext, cx_b: &mut T editor_b.update(cx_b, |editor, cx| { assert_eq!(editor.selections.ranges(cx), vec![1..1]) }); - cx_b.update(|cx| { + cx_b.update(|_, cx| { let room = ActiveCall::global(cx).read(cx).room().unwrap().read(cx); let participant = room.remote_participants().get(&client_a.id()).unwrap(); assert_eq!(participant.location, ParticipantLocation::UnsharedProject) @@ -1703,16 +1751,16 @@ async fn test_following_into_excluded_file( // Client A opens editors for a regular file and an excluded file. let editor_for_regular = workspace_a - .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, "1.txt"), None, true, cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.open_path((worktree_id, "1.txt"), None, true, window, cx) }) .await .unwrap() .downcast::() .unwrap(); let editor_for_excluded_a = workspace_a - .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, ".git/COMMIT_EDITMSG"), None, true, cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.open_path((worktree_id, ".git/COMMIT_EDITMSG"), None, true, window, cx) }) .await .unwrap() @@ -1720,22 +1768,24 @@ async fn test_following_into_excluded_file( .unwrap(); // Client A updates their selections in those editors - editor_for_regular.update(cx_a, |editor, cx| { - editor.handle_input("a", cx); - editor.handle_input("b", cx); - editor.handle_input("c", cx); - editor.select_left(&Default::default(), cx); + editor_for_regular.update_in(cx_a, |editor, window, cx| { + editor.handle_input("a", window, cx); + editor.handle_input("b", window, cx); + editor.handle_input("c", window, cx); + editor.select_left(&Default::default(), window, cx); assert_eq!(editor.selections.ranges(cx), vec![3..2]); }); - editor_for_excluded_a.update(cx_a, |editor, cx| { - editor.select_all(&Default::default(), cx); - editor.handle_input("new commit message", cx); - editor.select_left(&Default::default(), cx); + editor_for_excluded_a.update_in(cx_a, |editor, window, cx| { + editor.select_all(&Default::default(), window, cx); + editor.handle_input("new commit message", window, cx); + editor.select_left(&Default::default(), window, cx); assert_eq!(editor.selections.ranges(cx), vec![18..17]); }); // When client B starts following client A, currently visible file is replicated - workspace_b.update(cx_b, |workspace, cx| workspace.follow(peer_id_a, cx)); + workspace_b.update_in(cx_b, |workspace, window, cx| { + workspace.follow(peer_id_a, window, cx) + }); executor.advance_clock(workspace::item::LEADER_UPDATE_THROTTLE); executor.run_until_parked(); @@ -1755,15 +1805,15 @@ async fn test_following_into_excluded_file( vec![18..17] ); - editor_for_excluded_a.update(cx_a, |editor, cx| { - editor.select_right(&Default::default(), cx); + editor_for_excluded_a.update_in(cx_a, |editor, window, cx| { + editor.select_right(&Default::default(), window, cx); }); executor.advance_clock(workspace::item::LEADER_UPDATE_THROTTLE); executor.run_until_parked(); // Changes from B to the excluded file are replicated in A's editor - editor_for_excluded_b.update(cx_b, |editor, cx| { - editor.handle_input("\nCo-Authored-By: B ", cx); + editor_for_excluded_b.update_in(cx_b, |editor, window, cx| { + editor.handle_input("\nCo-Authored-By: B ", window, cx); }); executor.run_until_parked(); editor_for_excluded_a.update(cx_a, |editor, cx| { @@ -1774,13 +1824,11 @@ async fn test_following_into_excluded_file( }); } -fn visible_push_notifications( - cx: &mut TestAppContext, -) -> Vec> { +fn visible_push_notifications(cx: &mut TestAppContext) -> Vec> { let mut ret = Vec::new(); for window in cx.windows() { window - .update(cx, |window, _| { + .update(cx, |window, _, _| { if let Ok(handle) = window.downcast::() { ret.push(handle) } @@ -1821,7 +1869,7 @@ fn followers_by_leader(project_id: u64, cx: &TestAppContext) -> Vec<(PeerId, Vec }) } -fn pane_summaries(workspace: &View, cx: &mut VisualTestContext) -> Vec { +fn pane_summaries(workspace: &Entity, cx: &mut VisualTestContext) -> Vec { workspace.update(cx, |workspace, cx| { let active_pane = workspace.active_pane(); workspace @@ -1924,14 +1972,14 @@ async fn test_following_to_channel_notes_without_a_shared_project( // Client A opens the notes for channel 1. let channel_notes_1_a = cx_a - .update(|cx| ChannelView::open(channel_1_id, None, workspace_a.clone(), cx)) + .update(|window, cx| ChannelView::open(channel_1_id, None, workspace_a.clone(), window, cx)) .await .unwrap(); - channel_notes_1_a.update(cx_a, |notes, cx| { + channel_notes_1_a.update_in(cx_a, |notes, window, cx| { assert_eq!(notes.channel(cx).unwrap().name, "channel-1"); notes.editor.update(cx, |editor, cx| { - editor.insert("Hello from A.", cx); - editor.change_selections(None, cx, |selections| { + editor.insert("Hello from A.", window, cx); + editor.change_selections(None, window, cx, |selections| { selections.select_ranges(vec![3..4]); }); }); @@ -1939,9 +1987,9 @@ async fn test_following_to_channel_notes_without_a_shared_project( // Client B follows client A. workspace_b - .update(cx_b, |workspace, cx| { + .update_in(cx_b, |workspace, window, cx| { workspace - .start_following(client_a.peer_id().unwrap(), cx) + .start_following(client_a.peer_id().unwrap(), window, cx) .unwrap() }) .await @@ -1971,7 +2019,7 @@ async fn test_following_to_channel_notes_without_a_shared_project( // Client A opens the notes for channel 2. let channel_notes_2_a = cx_a - .update(|cx| ChannelView::open(channel_2_id, None, workspace_a.clone(), cx)) + .update(|window, cx| ChannelView::open(channel_2_id, None, workspace_a.clone(), window, cx)) .await .unwrap(); channel_notes_2_a.update(cx_a, |notes, cx| { @@ -1997,8 +2045,8 @@ async fn test_following_to_channel_notes_without_a_shared_project( // Client A opens a local buffer in their unshared project. let _unshared_editor_a1 = workspace_a - .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, "1.txt"), None, true, cx) + .update_in(cx_a, |workspace, window, cx| { + workspace.open_path((worktree_id, "1.txt"), None, true, window, cx) }) .await .unwrap() @@ -2027,7 +2075,7 @@ pub(crate) async fn join_channel( } async fn share_workspace( - workspace: &View, + workspace: &Entity, cx: &mut VisualTestContext, ) -> anyhow::Result { let project = workspace.update(cx, |workspace, _| workspace.project().clone()); @@ -2069,9 +2117,9 @@ async fn test_following_to_channel_notes_other_workspace( // a opens a second workspace and the channel notes let (workspace_a2, cx_a2) = client_a.build_test_workspace(&mut cx_a2).await; - cx_a2.update(|cx| cx.activate_window()); + cx_a2.update(|window, _| window.activate_window()); cx_a2 - .update(|cx| ChannelView::open(channel, None, workspace_a2, cx)) + .update(|window, cx| ChannelView::open(channel, None, workspace_a2, window, cx)) .await .unwrap(); cx_a2.run_until_parked(); @@ -2083,7 +2131,7 @@ async fn test_following_to_channel_notes_other_workspace( }); // a returns to the shared project - cx_a.update(|cx| cx.activate_window()); + cx_a.update(|window, _| window.activate_window()); cx_a.run_until_parked(); workspace_a.update(cx_a, |workspace, cx| { @@ -2141,7 +2189,7 @@ async fn test_following_while_deactivated(cx_a: &mut TestAppContext, cx_b: &mut // a opens a file in a new window let (_, cx_a2) = client_a.build_test_workspace(&mut cx_a2).await; - cx_a2.update(|cx| cx.activate_window()); + cx_a2.update(|window, _| window.activate_window()); cx_a2.simulate_keystrokes("cmd-p"); cx_a2.run_until_parked(); cx_a2.simulate_keystrokes("3 enter"); @@ -2152,7 +2200,7 @@ async fn test_following_while_deactivated(cx_a: &mut TestAppContext, cx_b: &mut cx_a.run_until_parked(); // a returns to the shared project - cx_a.update(|cx| cx.activate_window()); + cx_a.update(|window, _| window.activate_window()); cx_a.run_until_parked(); workspace_a.update(cx_a, |workspace, cx| { diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 1c151a730c..fbc1943c97 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -18,7 +18,7 @@ use prompt_library::PromptBuilder; use git::status::{FileStatus, StatusCode, TrackedStatus, UnmergedStatus, UnmergedStatusCode}; use gpui::{ - px, size, AppContext, BackgroundExecutor, Model, Modifiers, MouseButton, MouseDownEvent, + px, size, App, BackgroundExecutor, Entity, Modifiers, MouseButton, MouseDownEvent, TestAppContext, UpdateGlobal, }; use language::{ @@ -2073,7 +2073,7 @@ async fn test_mute_deafen( } fn participant_audio_state( - room: &Model, + room: &Entity, cx: &TestAppContext, ) -> Vec { room.read_with(cx, |room, _| { @@ -2252,7 +2252,7 @@ async fn test_room_location( ); fn participant_locations( - room: &Model, + room: &Entity, cx: &TestAppContext, ) -> Vec<(String, ParticipantLocation)> { room.read_with(cx, |room, _| { @@ -2821,7 +2821,7 @@ async fn test_git_branch_name( executor.run_until_parked(); #[track_caller] - fn assert_branch(branch_name: Option>, project: &Project, cx: &AppContext) { + fn assert_branch(branch_name: Option>, project: &Project, cx: &App) { let branch_name = branch_name.map(Into::into); let worktrees = project.visible_worktrees(cx).collect::>(); assert_eq!(worktrees.len(), 1); @@ -2931,7 +2931,7 @@ async fn test_git_status_sync( file: &impl AsRef, status: Option, project: &Project, - cx: &AppContext, + cx: &App, ) { let file = file.as_ref(); let worktrees = project.visible_worktrees(cx).collect::>(); @@ -6167,7 +6167,7 @@ async fn test_right_click_menu_behind_collab_panel(cx: &mut TestAppContext) { cx.simulate_resize(size(px(300.), px(300.))); cx.simulate_keystrokes("cmd-n cmd-n cmd-n"); - cx.update(|cx| cx.refresh()); + cx.update(|window, _cx| window.refresh()); let tab_bounds = cx.debug_bounds("TAB-2").unwrap(); let new_tab_button_bounds = cx.debug_bounds("ICON-Plus").unwrap(); @@ -6260,14 +6260,14 @@ async fn test_preview_tabs(cx: &mut TestAppContext) { let pane = workspace.update(cx, |workspace, _| workspace.active_pane().clone()); - let get_path = |pane: &Pane, idx: usize, cx: &AppContext| { + let get_path = |pane: &Pane, idx: usize, cx: &App| { pane.item_for_index(idx).unwrap().project_path(cx).unwrap() }; // Opening item 3 as a "permanent" tab workspace - .update(cx, |workspace, cx| { - workspace.open_path(path_3.clone(), None, false, cx) + .update_in(cx, |workspace, window, cx| { + workspace.open_path(path_3.clone(), None, false, window, cx) }) .await .unwrap(); @@ -6283,8 +6283,8 @@ async fn test_preview_tabs(cx: &mut TestAppContext) { // Open item 1 as preview workspace - .update(cx, |workspace, cx| { - workspace.open_path_preview(path_1.clone(), None, true, true, cx) + .update_in(cx, |workspace, window, cx| { + workspace.open_path_preview(path_1.clone(), None, true, true, window, cx) }) .await .unwrap(); @@ -6304,8 +6304,8 @@ async fn test_preview_tabs(cx: &mut TestAppContext) { // Open item 2 as preview workspace - .update(cx, |workspace, cx| { - workspace.open_path_preview(path_2.clone(), None, true, true, cx) + .update_in(cx, |workspace, window, cx| { + workspace.open_path_preview(path_2.clone(), None, true, true, window, cx) }) .await .unwrap(); @@ -6325,7 +6325,9 @@ async fn test_preview_tabs(cx: &mut TestAppContext) { // Going back should show item 1 as preview workspace - .update(cx, |workspace, cx| workspace.go_back(pane.downgrade(), cx)) + .update_in(cx, |workspace, window, cx| { + workspace.go_back(pane.downgrade(), window, cx) + }) .await .unwrap(); @@ -6343,10 +6345,11 @@ async fn test_preview_tabs(cx: &mut TestAppContext) { }); // Closing item 1 - pane.update(cx, |pane, cx| { + pane.update_in(cx, |pane, window, cx| { pane.close_item_by_id( pane.active_item().unwrap().item_id(), workspace::SaveIntent::Skip, + window, cx, ) }) @@ -6364,7 +6367,9 @@ async fn test_preview_tabs(cx: &mut TestAppContext) { // Going back should show item 1 as preview workspace - .update(cx, |workspace, cx| workspace.go_back(pane.downgrade(), cx)) + .update_in(cx, |workspace, window, cx| { + workspace.go_back(pane.downgrade(), window, cx) + }) .await .unwrap(); @@ -6382,9 +6387,9 @@ async fn test_preview_tabs(cx: &mut TestAppContext) { }); // Close permanent tab - pane.update(cx, |pane, cx| { + pane.update_in(cx, |pane, window, cx| { let id = pane.items().next().unwrap().item_id(); - pane.close_item_by_id(id, workspace::SaveIntent::Skip, cx) + pane.close_item_by_id(id, workspace::SaveIntent::Skip, window, cx) }) .await .unwrap(); @@ -6431,8 +6436,8 @@ async fn test_preview_tabs(cx: &mut TestAppContext) { // Open item 2 as preview in right pane workspace - .update(cx, |workspace, cx| { - workspace.open_path_preview(path_2.clone(), None, true, true, cx) + .update_in(cx, |workspace, window, cx| { + workspace.open_path_preview(path_2.clone(), None, true, true, window, cx) }) .await .unwrap(); @@ -6463,14 +6468,14 @@ async fn test_preview_tabs(cx: &mut TestAppContext) { }); // Focus left pane - workspace.update(cx, |workspace, cx| { - workspace.activate_pane_in_direction(workspace::SplitDirection::Left, cx) + workspace.update_in(cx, |workspace, window, cx| { + workspace.activate_pane_in_direction(workspace::SplitDirection::Left, window, cx) }); // Open item 2 as preview in left pane workspace - .update(cx, |workspace, cx| { - workspace.open_path_preview(path_2.clone(), None, true, true, cx) + .update_in(cx, |workspace, window, cx| { + workspace.open_path_preview(path_2.clone(), None, true, true, window, cx) }) .await .unwrap(); diff --git a/crates/collab/src/tests/notification_tests.rs b/crates/collab/src/tests/notification_tests.rs index ddbc1d197b..eb1c56eeb8 100644 --- a/crates/collab/src/tests/notification_tests.rs +++ b/crates/collab/src/tests/notification_tests.rs @@ -21,14 +21,14 @@ async fn test_notifications( let notification_events_b = Arc::new(Mutex::new(Vec::new())); client_a.notification_store().update(cx_a, |_, cx| { let events = notification_events_a.clone(); - cx.subscribe(&cx.handle(), move |_, _, event, _| { + cx.subscribe(&cx.model(), move |_, _, event, _| { events.lock().push(event.clone()); }) .detach() }); client_b.notification_store().update(cx_b, |_, cx| { let events = notification_events_b.clone(); - cx.subscribe(&cx.handle(), move |_, _, event, _| { + cx.subscribe(&cx.model(), move |_, _, event, _| { events.lock().push(event.clone()); }) .detach() diff --git a/crates/collab/src/tests/random_project_collaboration_tests.rs b/crates/collab/src/tests/random_project_collaboration_tests.rs index 774c105c8f..b250473b61 100644 --- a/crates/collab/src/tests/random_project_collaboration_tests.rs +++ b/crates/collab/src/tests/random_project_collaboration_tests.rs @@ -7,7 +7,7 @@ use collections::{BTreeMap, HashMap}; use editor::Bias; use fs::{FakeFs, Fs as _}; use git::status::{FileStatus, StatusCode, TrackedStatus, UnmergedStatus, UnmergedStatusCode}; -use gpui::{BackgroundExecutor, Model, TestAppContext}; +use gpui::{BackgroundExecutor, Entity, TestAppContext}; use language::{ range_to_lsp, FakeLspAdapter, Language, LanguageConfig, LanguageMatcher, PointUtf16, }; @@ -1475,10 +1475,10 @@ fn generate_git_operation(rng: &mut StdRng, client: &TestClient) -> GitOperation fn buffer_for_full_path( client: &TestClient, - project: &Model, + project: &Entity, full_path: &PathBuf, cx: &TestAppContext, -) -> Option> { +) -> Option> { client .buffers_for_project(project) .iter() @@ -1494,7 +1494,7 @@ fn project_for_root_name( client: &TestClient, root_name: &str, cx: &TestAppContext, -) -> Option> { +) -> Option> { if let Some(ix) = project_ix_for_root_name(client.local_projects().deref(), root_name, cx) { return Some(client.local_projects()[ix].clone()); } @@ -1506,7 +1506,7 @@ fn project_for_root_name( } fn project_ix_for_root_name( - projects: &[Model], + projects: &[Entity], root_name: &str, cx: &TestAppContext, ) -> Option { @@ -1518,7 +1518,7 @@ fn project_ix_for_root_name( }) } -fn root_name_for_project(project: &Model, cx: &TestAppContext) -> String { +fn root_name_for_project(project: &Entity, cx: &TestAppContext) -> String { project.read_with(cx, |project, cx| { project .visible_worktrees(cx) @@ -1531,7 +1531,7 @@ fn root_name_for_project(project: &Model, cx: &TestAppContext) -> Strin } fn project_path_for_full_path( - project: &Model, + project: &Entity, full_path: &Path, cx: &TestAppContext, ) -> Option { @@ -1552,7 +1552,7 @@ fn project_path_for_full_path( } async fn ensure_project_shared( - project: &Model, + project: &Entity, client: &TestClient, cx: &mut TestAppContext, ) { @@ -1585,7 +1585,7 @@ async fn ensure_project_shared( } } -fn choose_random_project(client: &TestClient, rng: &mut StdRng) -> Option> { +fn choose_random_project(client: &TestClient, rng: &mut StdRng) -> Option> { client .local_projects() .deref() diff --git a/crates/collab/src/tests/remote_editing_collaboration_tests.rs b/crates/collab/src/tests/remote_editing_collaboration_tests.rs index 30fa54935e..c251204459 100644 --- a/crates/collab/src/tests/remote_editing_collaboration_tests.rs +++ b/crates/collab/src/tests/remote_editing_collaboration_tests.rs @@ -4,7 +4,9 @@ use collections::HashSet; use extension::ExtensionHostProxy; use fs::{FakeFs, Fs as _}; use futures::StreamExt as _; -use gpui::{BackgroundExecutor, Context as _, SemanticVersion, TestAppContext, UpdateGlobal as _}; +use gpui::{ + AppContext as _, BackgroundExecutor, SemanticVersion, TestAppContext, UpdateGlobal as _, +}; use http_client::BlockedHttpClient; use language::{ language_settings::{ @@ -73,7 +75,7 @@ async fn test_sharing_an_ssh_remote_project( let remote_http_client = Arc::new(BlockedHttpClient); let node = NodeRuntime::unavailable(); let languages = Arc::new(LanguageRegistry::new(server_cx.executor())); - let _headless_project = server_cx.new_model(|cx| { + let _headless_project = server_cx.new(|cx| { client::init_settings(cx); HeadlessProject::new( HeadlessAppState { @@ -240,7 +242,7 @@ async fn test_ssh_collaboration_git_branches( let remote_http_client = Arc::new(BlockedHttpClient); let node = NodeRuntime::unavailable(); let languages = Arc::new(LanguageRegistry::new(server_cx.executor())); - let headless_project = server_cx.new_model(|cx| { + let headless_project = server_cx.new(|cx| { client::init_settings(cx); HeadlessProject::new( HeadlessAppState { @@ -398,7 +400,7 @@ async fn test_ssh_collaboration_formatting_with_prettier( // User A connects to the remote project via SSH. server_cx.update(HeadlessProject::init); let remote_http_client = Arc::new(BlockedHttpClient); - let _headless_project = server_cx.new_model(|cx| { + let _headless_project = server_cx.new(|cx| { client::init_settings(cx); HeadlessProject::new( HeadlessAppState { diff --git a/crates/collab/src/tests/test_server.rs b/crates/collab/src/tests/test_server.rs index 13905ead3c..64e0319cbb 100644 --- a/crates/collab/src/tests/test_server.rs +++ b/crates/collab/src/tests/test_server.rs @@ -17,7 +17,7 @@ use collections::{HashMap, HashSet}; use fs::FakeFs; use futures::{channel::oneshot, StreamExt as _}; use git::GitHostingProviderRegistry; -use gpui::{BackgroundExecutor, Context, Model, Task, TestAppContext, View, VisualTestContext}; +use gpui::{AppContext as _, BackgroundExecutor, Entity, Task, TestAppContext, VisualTestContext}; use http_client::FakeHttpClient; use language::LanguageRegistry; use node_runtime::NodeRuntime; @@ -64,17 +64,17 @@ pub struct TestServer { pub struct TestClient { pub username: String, pub app_state: Arc, - channel_store: Model, - notification_store: Model, + channel_store: Entity, + notification_store: Entity, state: RefCell, } #[derive(Default)] struct TestClientState { - local_projects: Vec>, - dev_server_projects: Vec>, - buffers: HashMap, HashSet>>, - channel_buffers: HashSet>, + local_projects: Vec>, + dev_server_projects: Vec>, + buffers: HashMap, HashSet>>, + channel_buffers: HashSet>, } pub struct ContactsSummary { @@ -274,10 +274,10 @@ impl TestServer { git_hosting_provider_registry .register_hosting_provider(Arc::new(git_hosting_providers::Github)); - let user_store = cx.new_model(|cx| UserStore::new(client.clone(), cx)); - let workspace_store = cx.new_model(|cx| WorkspaceStore::new(client.clone(), cx)); + let user_store = cx.new(|cx| UserStore::new(client.clone(), cx)); + let workspace_store = cx.new(|cx| WorkspaceStore::new(client.clone(), cx)); let language_registry = Arc::new(LanguageRegistry::test(cx.executor())); - let session = cx.new_model(|cx| AppSession::new(Session::test(), cx)); + let session = cx.new(|cx| AppSession::new(Session::test(), cx)); let app_state = Arc::new(workspace::AppState { client: client.clone(), user_store: user_store.clone(), @@ -596,15 +596,15 @@ impl TestClient { self.app_state.fs.as_fake() } - pub fn channel_store(&self) -> &Model { + pub fn channel_store(&self) -> &Entity { &self.channel_store } - pub fn notification_store(&self) -> &Model { + pub fn notification_store(&self) -> &Entity { &self.notification_store } - pub fn user_store(&self) -> &Model { + pub fn user_store(&self) -> &Entity { &self.app_state.user_store } @@ -639,19 +639,19 @@ impl TestClient { .await; } - pub fn local_projects(&self) -> impl Deref>> + '_ { + pub fn local_projects(&self) -> impl Deref>> + '_ { Ref::map(self.state.borrow(), |state| &state.local_projects) } - pub fn dev_server_projects(&self) -> impl Deref>> + '_ { + pub fn dev_server_projects(&self) -> impl Deref>> + '_ { Ref::map(self.state.borrow(), |state| &state.dev_server_projects) } - pub fn local_projects_mut(&self) -> impl DerefMut>> + '_ { + pub fn local_projects_mut(&self) -> impl DerefMut>> + '_ { RefMut::map(self.state.borrow_mut(), |state| &mut state.local_projects) } - pub fn dev_server_projects_mut(&self) -> impl DerefMut>> + '_ { + pub fn dev_server_projects_mut(&self) -> impl DerefMut>> + '_ { RefMut::map(self.state.borrow_mut(), |state| { &mut state.dev_server_projects }) @@ -659,8 +659,8 @@ impl TestClient { pub fn buffers_for_project<'a>( &'a self, - project: &Model, - ) -> impl DerefMut>> + 'a { + project: &Entity, + ) -> impl DerefMut>> + 'a { RefMut::map(self.state.borrow_mut(), |state| { state.buffers.entry(project.clone()).or_default() }) @@ -668,12 +668,12 @@ impl TestClient { pub fn buffers( &self, - ) -> impl DerefMut, HashSet>>> + '_ + ) -> impl DerefMut, HashSet>>> + '_ { RefMut::map(self.state.borrow_mut(), |state| &mut state.buffers) } - pub fn channel_buffers(&self) -> impl DerefMut>> + '_ { + pub fn channel_buffers(&self) -> impl DerefMut>> + '_ { RefMut::map(self.state.borrow_mut(), |state| &mut state.channel_buffers) } @@ -703,7 +703,7 @@ impl TestClient { &self, root_path: impl AsRef, cx: &mut TestAppContext, - ) -> (Model, WorktreeId) { + ) -> (Entity, WorktreeId) { let project = self.build_empty_local_project(cx); let (worktree, _) = project .update(cx, |p, cx| p.find_or_create_worktree(root_path, true, cx)) @@ -718,9 +718,9 @@ impl TestClient { pub async fn build_ssh_project( &self, root_path: impl AsRef, - ssh: Model, + ssh: Entity, cx: &mut TestAppContext, - ) -> (Model, WorktreeId) { + ) -> (Entity, WorktreeId) { let project = cx.update(|cx| { Project::ssh( ssh, @@ -739,7 +739,7 @@ impl TestClient { (project, worktree.read_with(cx, |tree, _| tree.id())) } - pub async fn build_test_project(&self, cx: &mut TestAppContext) -> Model { + pub async fn build_test_project(&self, cx: &mut TestAppContext) -> Entity { self.fs() .insert_tree( "/a", @@ -755,17 +755,17 @@ impl TestClient { pub async fn host_workspace( &self, - workspace: &View, + workspace: &Entity, channel_id: ChannelId, cx: &mut VisualTestContext, ) { - cx.update(|cx| { + cx.update(|_, cx| { let active_call = ActiveCall::global(cx); active_call.update(cx, |call, cx| call.join_channel(channel_id, cx)) }) .await .unwrap(); - cx.update(|cx| { + cx.update(|_, cx| { let active_call = ActiveCall::global(cx); let project = workspace.read(cx).project().clone(); active_call.update(cx, |call, cx| call.share_project(project, cx)) @@ -779,7 +779,7 @@ impl TestClient { &'a self, channel_id: ChannelId, cx: &'a mut TestAppContext, - ) -> (View, &'a mut VisualTestContext) { + ) -> (Entity, &'a mut VisualTestContext) { cx.update(|cx| workspace::join_channel(channel_id, self.app_state.clone(), None, cx)) .await .unwrap(); @@ -788,7 +788,7 @@ impl TestClient { self.active_workspace(cx) } - pub fn build_empty_local_project(&self, cx: &mut TestAppContext) -> Model { + pub fn build_empty_local_project(&self, cx: &mut TestAppContext) -> Entity { cx.update(|cx| { Project::local( self.client().clone(), @@ -806,7 +806,7 @@ impl TestClient { &self, host_project_id: u64, guest_cx: &mut TestAppContext, - ) -> Model { + ) -> Entity { let active_call = guest_cx.read(ActiveCall::global); let room = active_call.read_with(guest_cx, |call, _| call.room().unwrap().clone()); room.update(guest_cx, |room, cx| { @@ -823,47 +823,47 @@ impl TestClient { pub fn build_workspace<'a>( &'a self, - project: &Model, + project: &Entity, cx: &'a mut TestAppContext, - ) -> (View, &'a mut VisualTestContext) { - cx.add_window_view(|cx| { - cx.activate_window(); - Workspace::new(None, project.clone(), self.app_state.clone(), cx) + ) -> (Entity, &'a mut VisualTestContext) { + cx.add_window_view(|window, cx| { + window.activate_window(); + Workspace::new(None, project.clone(), self.app_state.clone(), window, cx) }) } pub async fn build_test_workspace<'a>( &'a self, cx: &'a mut TestAppContext, - ) -> (View, &'a mut VisualTestContext) { + ) -> (Entity, &'a mut VisualTestContext) { let project = self.build_test_project(cx).await; - cx.add_window_view(|cx| { - cx.activate_window(); - Workspace::new(None, project.clone(), self.app_state.clone(), cx) + cx.add_window_view(|window, cx| { + window.activate_window(); + Workspace::new(None, project.clone(), self.app_state.clone(), window, cx) }) } pub fn active_workspace<'a>( &'a self, cx: &'a mut TestAppContext, - ) -> (View, &'a mut VisualTestContext) { + ) -> (Entity, &'a mut VisualTestContext) { let window = cx.update(|cx| cx.active_window().unwrap().downcast::().unwrap()); - let view = window.root_view(cx).unwrap(); + let model = window.root_model(cx).unwrap(); let cx = VisualTestContext::from_window(*window.deref(), cx).as_mut(); // it might be nice to try and cleanup these at the end of each test. - (view, cx) + (model, cx) } } pub fn open_channel_notes( channel_id: ChannelId, cx: &mut VisualTestContext, -) -> Task>> { - let window = cx.update(|cx| cx.active_window().unwrap().downcast::().unwrap()); - let view = window.root_view(cx).unwrap(); +) -> Task>> { + let window = cx.update(|_, cx| cx.active_window().unwrap().downcast::().unwrap()); + let model = window.root_model(cx).unwrap(); - cx.update(|cx| ChannelView::open(channel_id, None, view.clone(), cx)) + cx.update(|window, cx| ChannelView::open(channel_id, None, model.clone(), window, cx)) } impl Drop for TestClient { diff --git a/crates/collab/src/user_backfiller.rs b/crates/collab/src/user_backfiller.rs index 277e9dc80e..dcabe8d216 100644 --- a/crates/collab/src/user_backfiller.rs +++ b/crates/collab/src/user_backfiller.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, Context as _, Result}; use chrono::{DateTime, Utc}; use util::ResultExt; diff --git a/crates/collab_ui/src/channel_view.rs b/crates/collab_ui/src/channel_view.rs index e12e4b3262..2e10868628 100644 --- a/crates/collab_ui/src/channel_view.rs +++ b/crates/collab_ui/src/channel_view.rs @@ -11,9 +11,8 @@ use editor::{ EditorEvent, }; use gpui::{ - actions, AnyView, AppContext, ClipboardItem, Entity as _, EventEmitter, FocusableView, Model, - Pixels, Point, Render, Subscription, Task, View, ViewContext, VisualContext as _, WeakView, - WindowContext, + actions, AnyView, App, ClipboardItem, Context, Entity, EventEmitter, Focusable, Pixels, Point, + Render, Subscription, Task, VisualContext as _, WeakEntity, Window, }; use project::Project; use rpc::proto::ChannelVisibility; @@ -33,16 +32,16 @@ use workspace::{ actions!(collab, [CopyLink]); -pub fn init(cx: &mut AppContext) { +pub fn init(cx: &mut App) { workspace::FollowableViewRegistry::register::(cx) } pub struct ChannelView { - pub editor: View, - workspace: WeakView, - project: Model, - channel_store: Model, - channel_buffer: Model, + pub editor: Entity, + workspace: WeakEntity, + project: Entity, + channel_store: Entity, + channel_buffer: Entity, remote_id: Option, _editor_event_subscription: Subscription, _reparse_subscription: Option, @@ -52,20 +51,22 @@ impl ChannelView { pub fn open( channel_id: ChannelId, link_position: Option, - workspace: View, - cx: &mut WindowContext, - ) -> Task>> { + workspace: Entity, + window: &mut Window, + cx: &mut App, + ) -> Task>> { let pane = workspace.read(cx).active_pane().clone(); let channel_view = Self::open_in_pane( channel_id, link_position, pane.clone(), workspace.clone(), + window, cx, ); - cx.spawn(|mut cx| async move { + window.spawn(cx, |mut cx| async move { let channel_view = channel_view.await?; - pane.update(&mut cx, |pane, cx| { + pane.update_in(&mut cx, |pane, window, cx| { telemetry::event!( "Channel Notes Opened", channel_id, @@ -74,7 +75,7 @@ impl ChannelView { .room() .map(|r| r.read(cx).id()) ); - pane.add_item(Box::new(channel_view.clone()), true, true, None, cx); + pane.add_item(Box::new(channel_view.clone()), true, true, None, window, cx); })?; anyhow::Ok(channel_view) }) @@ -83,15 +84,16 @@ impl ChannelView { pub fn open_in_pane( channel_id: ChannelId, link_position: Option, - pane: View, - workspace: View, - cx: &mut WindowContext, - ) -> Task>> { - let channel_view = Self::load(channel_id, workspace, cx); - cx.spawn(|mut cx| async move { + pane: Entity, + workspace: Entity, + window: &mut Window, + cx: &mut App, + ) -> Task>> { + let channel_view = Self::load(channel_id, workspace, window, cx); + window.spawn(cx, |mut cx| async move { let channel_view = channel_view.await?; - pane.update(&mut cx, |pane, cx| { + pane.update_in(&mut cx, |pane, window, cx| { let buffer_id = channel_view.read(cx).channel_buffer.read(cx).remote_id(cx); let existing_view = pane @@ -104,7 +106,12 @@ impl ChannelView { { if let Some(link_position) = link_position { existing_view.update(cx, |channel_view, cx| { - channel_view.focus_position_from_link(link_position, true, cx) + channel_view.focus_position_from_link( + link_position, + true, + window, + cx, + ) }); } return existing_view; @@ -115,15 +122,27 @@ impl ChannelView { // replace that. if let Some(existing_item) = existing_view { if let Some(ix) = pane.index_for_item(&existing_item) { - pane.close_item_by_id(existing_item.entity_id(), SaveIntent::Skip, cx) - .detach(); - pane.add_item(Box::new(channel_view.clone()), true, true, Some(ix), cx); + pane.close_item_by_id( + existing_item.entity_id(), + SaveIntent::Skip, + window, + cx, + ) + .detach(); + pane.add_item( + Box::new(channel_view.clone()), + true, + true, + Some(ix), + window, + cx, + ); } } if let Some(link_position) = link_position { channel_view.update(cx, |channel_view, cx| { - channel_view.focus_position_from_link(link_position, true, cx) + channel_view.focus_position_from_link(link_position, true, window, cx) }); } @@ -134,9 +153,10 @@ impl ChannelView { pub fn load( channel_id: ChannelId, - workspace: View, - cx: &mut WindowContext, - ) -> Task>> { + workspace: Entity, + window: &mut Window, + cx: &mut App, + ) -> Task>> { let weak_workspace = workspace.downgrade(); let workspace = workspace.read(cx); let project = workspace.project().to_owned(); @@ -146,7 +166,7 @@ impl ChannelView { let channel_buffer = channel_store.update(cx, |store, cx| store.open_channel_buffer(channel_id, cx)); - cx.spawn(|mut cx| async move { + window.spawn(cx, |mut cx| async move { let channel_buffer = channel_buffer.await?; let markdown = markdown.await.log_err(); @@ -160,9 +180,15 @@ impl ChannelView { }) })?; - cx.new_view(|cx| { - let mut this = - Self::new(project, weak_workspace, channel_store, channel_buffer, cx); + cx.new_window_model(|window, cx| { + let mut this = Self::new( + project, + weak_workspace, + channel_store, + channel_buffer, + window, + cx, + ); this.acknowledge_buffer_version(cx); this }) @@ -170,25 +196,28 @@ impl ChannelView { } pub fn new( - project: Model, - workspace: WeakView, - channel_store: Model, - channel_buffer: Model, - cx: &mut ViewContext, + project: Entity, + workspace: WeakEntity, + channel_store: Entity, + channel_buffer: Entity, + window: &mut Window, + cx: &mut Context, ) -> Self { let buffer = channel_buffer.read(cx).buffer(); - let this = cx.view().downgrade(); - let editor = cx.new_view(|cx| { - let mut editor = Editor::for_buffer(buffer, None, cx); + let this = cx.model().downgrade(); + let editor = cx.new(|cx| { + let mut editor = Editor::for_buffer(buffer, None, window, cx); editor.set_collaboration_hub(Box::new(ChannelBufferCollaborationHub( channel_buffer.clone(), ))); - editor.set_custom_context_menu(move |_, position, cx| { + editor.set_custom_context_menu(move |_, position, window, cx| { let this = this.clone(); - Some(ui::ContextMenu::build(cx, move |menu, _| { - menu.entry("Copy link to section", None, move |cx| { - this.update(cx, |this, cx| this.copy_link_for_position(position, cx)) - .ok(); + Some(ui::ContextMenu::build(window, cx, move |menu, _, _| { + menu.entry("Copy link to section", None, move |window, cx| { + this.update(cx, |this, cx| { + this.copy_link_for_position(position, window, cx) + }) + .ok(); }) })) }); @@ -197,7 +226,7 @@ impl ChannelView { let _editor_event_subscription = cx.subscribe(&editor, |_, _, e: &EditorEvent, cx| cx.emit(e.clone())); - cx.subscribe(&channel_buffer, Self::handle_channel_buffer_event) + cx.subscribe_in(&channel_buffer, window, Self::handle_channel_buffer_event) .detach(); Self { @@ -216,10 +245,13 @@ impl ChannelView { &mut self, position: String, first_attempt: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let position = Channel::slug(&position).to_lowercase(); - let snapshot = self.editor.update(cx, |editor, cx| editor.snapshot(cx)); + let snapshot = self + .editor + .update(cx, |editor, cx| editor.snapshot(window, cx)); if let Some(outline) = snapshot.buffer_snapshot.outline(None) { if let Some(item) = outline @@ -228,7 +260,7 @@ impl ChannelView { .find(|item| &Channel::slug(&item.text).to_lowercase() == &position) { self.editor.update(cx, |editor, cx| { - editor.change_selections(Some(Autoscroll::focused()), cx, |s| { + editor.change_selections(Some(Autoscroll::focused()), window, cx, |s| { s.replace_cursors_with(|map| vec![item.range.start.to_display_point(map)]) }) }); @@ -239,12 +271,13 @@ impl ChannelView { if !first_attempt { return; } - self._reparse_subscription = Some(cx.subscribe( + self._reparse_subscription = Some(cx.subscribe_in( &self.editor, - move |this, _, e: &EditorEvent, cx| { + window, + move |this, _, e: &EditorEvent, window, cx| { match e { EditorEvent::Reparsed(_) => { - this.focus_position_from_link(position.clone(), false, cx); + this.focus_position_from_link(position.clone(), false, window, cx); this._reparse_subscription.take(); } EditorEvent::Edited { .. } | EditorEvent::SelectionsChanged { local: true } => { @@ -256,15 +289,22 @@ impl ChannelView { )); } - fn copy_link(&mut self, _: &CopyLink, cx: &mut ViewContext) { + fn copy_link(&mut self, _: &CopyLink, window: &mut Window, cx: &mut Context) { let position = self .editor .update(cx, |editor, cx| editor.selections.newest_display(cx).start); - self.copy_link_for_position(position, cx) + self.copy_link_for_position(position, window, cx) } - fn copy_link_for_position(&self, position: DisplayPoint, cx: &mut ViewContext) { - let snapshot = self.editor.update(cx, |editor, cx| editor.snapshot(cx)); + fn copy_link_for_position( + &self, + position: DisplayPoint, + window: &mut Window, + cx: &mut Context, + ) { + let snapshot = self + .editor + .update(cx, |editor, cx| editor.snapshot(window, cx)); let mut closest_heading = None; @@ -298,15 +338,16 @@ impl ChannelView { .ok(); } - pub fn channel(&self, cx: &AppContext) -> Option> { + pub fn channel(&self, cx: &App) -> Option> { self.channel_buffer.read(cx).channel(cx) } fn handle_channel_buffer_event( &mut self, - _: Model, + _: &Entity, event: &ChannelBufferEvent, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { match event { ChannelBufferEvent::Disconnected => self.editor.update(cx, |editor, cx| { @@ -320,7 +361,7 @@ impl ChannelView { }); } ChannelBufferEvent::BufferEdited => { - if self.editor.read(cx).is_focused(cx) { + if self.editor.read(cx).is_focused(window) { self.acknowledge_buffer_version(cx); } else { self.channel_store.update(cx, |store, cx| { @@ -338,7 +379,7 @@ impl ChannelView { } } - fn acknowledge_buffer_version(&mut self, cx: &mut ViewContext) { + fn acknowledge_buffer_version(&mut self, cx: &mut Context) { self.channel_store.update(cx, |store, cx| { let channel_buffer = self.channel_buffer.read(cx); store.acknowledge_notes_version( @@ -357,7 +398,7 @@ impl ChannelView { impl EventEmitter for ChannelView {} impl Render for ChannelView { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { div() .size_full() .on_action(cx.listener(Self::copy_link)) @@ -365,8 +406,8 @@ impl Render for ChannelView { } } -impl FocusableView for ChannelView { - fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle { +impl Focusable for ChannelView { + fn focus_handle(&self, cx: &App) -> gpui::FocusHandle { self.editor.read(cx).focus_handle(cx) } } @@ -377,8 +418,8 @@ impl Item for ChannelView { fn act_as_type<'a>( &'a self, type_id: TypeId, - self_handle: &'a View, - _: &'a AppContext, + self_handle: &'a Entity, + _: &'a App, ) -> Option { if type_id == TypeId::of::() { Some(self_handle.to_any()) @@ -389,7 +430,7 @@ impl Item for ChannelView { } } - fn tab_icon(&self, cx: &WindowContext) -> Option { + fn tab_icon(&self, _: &Window, cx: &App) -> Option { let channel = self.channel(cx)?; let icon = match channel.visibility { ChannelVisibility::Public => IconName::Public, @@ -399,7 +440,7 @@ impl Item for ChannelView { Some(Icon::new(icon)) } - fn tab_content(&self, params: TabContentParams, cx: &WindowContext) -> gpui::AnyElement { + fn tab_content(&self, params: TabContentParams, _: &Window, cx: &App) -> gpui::AnyElement { let (channel_name, status) = if let Some(channel) = self.channel(cx) { let status = match ( self.channel_buffer.read(cx).buffer().read(cx).read_only(), @@ -439,38 +480,52 @@ impl Item for ChannelView { fn clone_on_split( &self, _: Option, - cx: &mut ViewContext, - ) -> Option> { - Some(cx.new_view(|cx| { + window: &mut Window, + cx: &mut Context, + ) -> Option> { + Some(cx.new(|cx| { Self::new( self.project.clone(), self.workspace.clone(), self.channel_store.clone(), self.channel_buffer.clone(), + window, cx, ) })) } - fn is_singleton(&self, _cx: &AppContext) -> bool { + fn is_singleton(&self, _cx: &App) -> bool { false } - fn navigate(&mut self, data: Box, cx: &mut ViewContext) -> bool { + fn navigate( + &mut self, + data: Box, + window: &mut Window, + cx: &mut Context, + ) -> bool { self.editor - .update(cx, |editor, cx| editor.navigate(data, cx)) + .update(cx, |editor, cx| editor.navigate(data, window, cx)) } - fn deactivated(&mut self, cx: &mut ViewContext) { - self.editor.update(cx, Item::deactivated) - } - - fn set_nav_history(&mut self, history: ItemNavHistory, cx: &mut ViewContext) { + fn deactivated(&mut self, window: &mut Window, cx: &mut Context) { self.editor - .update(cx, |editor, cx| Item::set_nav_history(editor, history, cx)) + .update(cx, |item, cx| item.deactivated(window, cx)) } - fn as_searchable(&self, _: &View) -> Option> { + fn set_nav_history( + &mut self, + history: ItemNavHistory, + window: &mut Window, + cx: &mut Context, + ) { + self.editor.update(cx, |editor, cx| { + Item::set_nav_history(editor, history, window, cx) + }) + } + + fn as_searchable(&self, _: &Entity) -> Option> { Some(Box::new(self.editor.clone())) } @@ -478,7 +533,7 @@ impl Item for ChannelView { true } - fn pixel_position_of_cursor(&self, cx: &AppContext) -> Option> { + fn pixel_position_of_cursor(&self, cx: &App) -> Option> { self.editor.read(cx).pixel_position_of_cursor(cx) } @@ -492,7 +547,7 @@ impl FollowableItem for ChannelView { self.remote_id } - fn to_state_proto(&self, cx: &WindowContext) -> Option { + fn to_state_proto(&self, window: &Window, cx: &App) -> Option { let channel_buffer = self.channel_buffer.read(cx); if !channel_buffer.is_connected() { return None; @@ -502,7 +557,7 @@ impl FollowableItem for ChannelView { proto::view::ChannelView { channel_id: channel_buffer.channel_id.0, editor: if let Some(proto::view::Variant::Editor(proto)) = - self.editor.read(cx).to_state_proto(cx) + self.editor.read(cx).to_state_proto(window, cx) { Some(proto) } else { @@ -513,11 +568,12 @@ impl FollowableItem for ChannelView { } fn from_state_proto( - workspace: View, + workspace: Entity, remote_id: workspace::ViewId, state: &mut Option, - cx: &mut WindowContext, - ) -> Option>>> { + window: &mut Window, + cx: &mut App, + ) -> Option>>> { let Some(proto::view::Variant::ChannelView(_)) = state else { return None; }; @@ -525,12 +581,12 @@ impl FollowableItem for ChannelView { unreachable!() }; - let open = ChannelView::load(ChannelId(state.channel_id), workspace, cx); + let open = ChannelView::load(ChannelId(state.channel_id), workspace, window, cx); - Some(cx.spawn(|mut cx| async move { + Some(window.spawn(cx, |mut cx| async move { let this = open.await?; - let task = this.update(&mut cx, |this, cx| { + let task = this.update_in(&mut cx, |this, window, cx| { this.remote_id = Some(remote_id); if let Some(state) = state.editor { @@ -545,6 +601,7 @@ impl FollowableItem for ChannelView { scroll_y: state.scroll_y, ..Default::default() }), + window, cx, ) })) @@ -565,31 +622,38 @@ impl FollowableItem for ChannelView { &self, event: &EditorEvent, update: &mut Option, - cx: &WindowContext, + window: &Window, + cx: &App, ) -> bool { self.editor .read(cx) - .add_event_to_update_proto(event, update, cx) + .add_event_to_update_proto(event, update, window, cx) } fn apply_update_proto( &mut self, - project: &Model, + project: &Entity, message: proto::update_view::Variant, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> gpui::Task> { self.editor.update(cx, |editor, cx| { - editor.apply_update_proto(project, message, cx) + editor.apply_update_proto(project, message, window, cx) }) } - fn set_leader_peer_id(&mut self, leader_peer_id: Option, cx: &mut ViewContext) { + fn set_leader_peer_id( + &mut self, + leader_peer_id: Option, + window: &mut Window, + cx: &mut Context, + ) { self.editor.update(cx, |editor, cx| { - editor.set_leader_peer_id(leader_peer_id, cx) + editor.set_leader_peer_id(leader_peer_id, window, cx) }) } - fn is_project_item(&self, _cx: &WindowContext) -> bool { + fn is_project_item(&self, _window: &Window, _cx: &App) -> bool { false } @@ -597,7 +661,7 @@ impl FollowableItem for ChannelView { Editor::to_follow_event(event) } - fn dedup(&self, existing: &Self, cx: &WindowContext) -> Option { + fn dedup(&self, existing: &Self, _: &Window, cx: &App) -> Option { let existing = existing.channel_buffer.read(cx); if self.channel_buffer.read(cx).channel_id == existing.channel_id { if existing.is_connected() { @@ -611,21 +675,18 @@ impl FollowableItem for ChannelView { } } -struct ChannelBufferCollaborationHub(Model); +struct ChannelBufferCollaborationHub(Entity); impl CollaborationHub for ChannelBufferCollaborationHub { - fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap { + fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap { self.0.read(cx).collaborators() } - fn user_participant_indices<'a>( - &self, - cx: &'a AppContext, - ) -> &'a HashMap { + fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap { self.0.read(cx).user_store().read(cx).participant_indices() } - fn user_names(&self, cx: &AppContext) -> HashMap { + fn user_names(&self, cx: &App) -> HashMap { let user_ids = self.collaborators(cx).values().map(|c| c.user_id); self.0 .read(cx) diff --git a/crates/collab_ui/src/chat_panel.rs b/crates/collab_ui/src/chat_panel.rs index daa1f1440d..52b5e35a98 100644 --- a/crates/collab_ui/src/chat_panel.rs +++ b/crates/collab_ui/src/chat_panel.rs @@ -7,10 +7,10 @@ use collections::HashMap; use db::kvp::KEY_VALUE_STORE; use editor::{actions, Editor}; use gpui::{ - actions, div, list, prelude::*, px, Action, AppContext, AsyncWindowContext, ClipboardItem, - CursorStyle, DismissEvent, ElementId, EventEmitter, FocusHandle, FocusableView, FontWeight, - HighlightStyle, ListOffset, ListScrollEvent, ListState, Model, Render, Stateful, Subscription, - Task, View, ViewContext, VisualContext, WeakView, + actions, div, list, prelude::*, px, Action, App, AsyncWindowContext, ClipboardItem, Context, + CursorStyle, DismissEvent, ElementId, Entity, EventEmitter, FocusHandle, Focusable, FontWeight, + HighlightStyle, ListOffset, ListScrollEvent, ListState, Render, Stateful, Subscription, Task, + WeakEntity, Window, }; use language::LanguageRegistry; use menu::Confirm; @@ -36,10 +36,10 @@ mod message_editor; const MESSAGE_LOADING_THRESHOLD: usize = 50; const CHAT_PANEL_KEY: &str = "ChatPanel"; -pub fn init(cx: &mut AppContext) { - cx.observe_new_views(|workspace: &mut Workspace, _| { - workspace.register_action(|workspace, _: &ToggleFocus, cx| { - workspace.toggle_panel_focus::(cx); +pub fn init(cx: &mut App) { + cx.observe_new(|workspace: &mut Workspace, _, _| { + workspace.register_action(|workspace, _: &ToggleFocus, window, cx| { + workspace.toggle_panel_focus::(window, cx); }); }) .detach(); @@ -47,11 +47,11 @@ pub fn init(cx: &mut AppContext) { pub struct ChatPanel { client: Arc, - channel_store: Model, + channel_store: Entity, languages: Arc, message_list: ListState, - active_chat: Option<(Model, Subscription)>, - message_editor: View, + active_chat: Option<(Entity, Subscription)>, + message_editor: Entity, local_timezone: UtcOffset, fs: Arc, width: Option, @@ -74,37 +74,46 @@ struct SerializedChatPanel { actions!(chat_panel, [ToggleFocus]); impl ChatPanel { - pub fn new(workspace: &mut Workspace, cx: &mut ViewContext) -> View { + pub fn new( + workspace: &mut Workspace, + window: &mut Window, + cx: &mut Context, + ) -> Entity { let fs = workspace.app_state().fs.clone(); let client = workspace.app_state().client.clone(); let channel_store = ChannelStore::global(cx); let user_store = workspace.app_state().user_store.clone(); let languages = workspace.app_state().languages.clone(); - let input_editor = cx.new_view(|cx| { + let input_editor = cx.new(|cx| { MessageEditor::new( languages.clone(), user_store.clone(), None, - cx.new_view(|cx| Editor::auto_height(4, cx)), + cx.new(|cx| Editor::auto_height(4, window, cx)), + window, cx, ) }); - cx.new_view(|cx: &mut ViewContext| { - let view = cx.view().downgrade(); - let message_list = - ListState::new(0, gpui::ListAlignment::Bottom, px(1000.), move |ix, cx| { - if let Some(view) = view.upgrade() { - view.update(cx, |view, cx| { - view.render_message(ix, cx).into_any_element() + cx.new(|cx| { + let model = cx.model().downgrade(); + let message_list = ListState::new( + 0, + gpui::ListAlignment::Bottom, + px(1000.), + move |ix, window, cx| { + if let Some(model) = model.upgrade() { + model.update(cx, |this: &mut Self, cx| { + this.render_message(ix, window, cx).into_any_element() }) } else { div().into_any() } - }); + }, + ); - message_list.set_scroll_handler(cx.listener(|this, event: &ListScrollEvent, cx| { + message_list.set_scroll_handler(cx.listener(|this, event: &ListScrollEvent, _, cx| { if event.visible_range.start < MESSAGE_LOADING_THRESHOLD { this.load_more_messages(cx); } @@ -172,7 +181,7 @@ impl ChatPanel { }) } - pub fn channel_id(&self, cx: &AppContext) -> Option { + pub fn channel_id(&self, cx: &App) -> Option { self.active_chat .as_ref() .map(|(chat, _)| chat.read(cx).channel_id) @@ -182,14 +191,14 @@ impl ChatPanel { self.is_scrolled_to_bottom } - pub fn active_chat(&self) -> Option> { + pub fn active_chat(&self) -> Option> { self.active_chat.as_ref().map(|(chat, _)| chat.clone()) } pub fn load( - workspace: WeakView, + workspace: WeakEntity, cx: AsyncWindowContext, - ) -> Task>> { + ) -> Task>> { cx.spawn(|mut cx| async move { let serialized_panel = if let Some(panel) = cx .background_executor() @@ -203,8 +212,8 @@ impl ChatPanel { None }; - workspace.update(&mut cx, |workspace, cx| { - let panel = Self::new(workspace, cx); + workspace.update_in(&mut cx, |workspace, window, cx| { + let panel = Self::new(workspace, window, cx); if let Some(serialized_panel) = serialized_panel { panel.update(cx, |panel, cx| { panel.width = serialized_panel.width.map(|r| r.round()); @@ -216,7 +225,7 @@ impl ChatPanel { }) } - fn serialize(&mut self, cx: &mut ViewContext) { + fn serialize(&mut self, cx: &mut Context) { let width = self.width; self.pending_serialization = cx.background_executor().spawn( async move { @@ -232,7 +241,7 @@ impl ChatPanel { ); } - fn set_active_chat(&mut self, chat: Model, cx: &mut ViewContext) { + fn set_active_chat(&mut self, chat: Entity, cx: &mut Context) { if self.active_chat.as_ref().map(|e| &e.0) != Some(&chat) { self.markdown_data.clear(); self.message_list.reset(chat.read(cx).message_count()); @@ -249,9 +258,9 @@ impl ChatPanel { fn channel_did_change( &mut self, - _: Model, + _: Entity, event: &ChannelChatEvent, - cx: &mut ViewContext, + cx: &mut Context, ) { match event { ChannelChatEvent::MessagesUpdated { @@ -284,7 +293,7 @@ impl ChatPanel { cx.notify(); } - fn acknowledge_last_message(&mut self, cx: &mut ViewContext) { + fn acknowledge_last_message(&mut self, cx: &mut Context) { if self.active && self.is_scrolled_to_bottom { if let Some((chat, _)) = &self.active_chat { if let Some(channel_id) = self.channel_id(cx) { @@ -305,7 +314,7 @@ impl ChatPanel { &mut self, message_id: Option, reply_to_message: &Option, - cx: &mut ViewContext, + cx: &mut Context, ) -> impl IntoElement { let reply_to_message = match reply_to_message { None => { @@ -369,8 +378,8 @@ impl ChatPanel { ), ) .cursor(CursorStyle::PointingHand) - .tooltip(|cx| Tooltip::text("Go to message", cx)) - .on_click(cx.listener(move |chat_panel, _, cx| { + .tooltip(Tooltip::text("Go to message")) + .on_click(cx.listener(move |chat_panel, _, _, cx| { if let Some(channel_id) = current_channel_id { chat_panel .select_channel(channel_id, reply_to_message_id.into(), cx) @@ -380,7 +389,12 @@ impl ChatPanel { ) } - fn render_message(&mut self, ix: usize, cx: &mut ViewContext) -> impl IntoElement { + fn render_message( + &mut self, + ix: usize, + window: &mut Window, + cx: &mut Context, + ) -> impl IntoElement { let active_chat = &self.active_chat.as_ref().unwrap().0; let (message, is_continuation_from_previous, is_admin) = active_chat.update(cx, |active_chat, cx| { @@ -530,7 +544,7 @@ impl ChatPanel { .w_full() .text_ui_sm(cx) .id(element_id) - .child(text.element("body".into(), cx)), + .child(text.element("body".into(), window, cx)), ) .when(self.has_open_menu(message_id), |el| { el.bg(cx.theme().colors().element_selected) @@ -560,7 +574,7 @@ impl ChatPanel { }, ) .child( - self.render_popover_buttons(cx, message_id, can_delete_message, can_edit_message) + self.render_popover_buttons(message_id, can_delete_message, can_edit_message, cx) .mt_neg_2p5(), ) } @@ -572,7 +586,7 @@ impl ChatPanel { } } - fn render_popover_button(&self, cx: &ViewContext, child: Stateful
) -> Div { + fn render_popover_button(&self, cx: &mut Context, child: Stateful
) -> Div { div() .w_6() .bg(cx.theme().colors().element_background) @@ -582,10 +596,10 @@ impl ChatPanel { fn render_popover_buttons( &self, - cx: &ViewContext, message_id: Option, can_delete_message: bool, can_edit_message: bool, + cx: &mut Context, ) -> Div { h_flex() .absolute() @@ -606,16 +620,16 @@ impl ChatPanel { .id("reply") .child( IconButton::new(("reply", message_id), IconName::ReplyArrowRight) - .on_click(cx.listener(move |this, _, cx| { + .on_click(cx.listener(move |this, _, window, cx| { this.cancel_edit_message(cx); this.message_editor.update(cx, |editor, cx| { editor.set_reply_to_message_id(message_id); - editor.focus_handle(cx).focus(cx); + window.focus(&editor.focus_handle(cx)); }) })), ) - .tooltip(|cx| Tooltip::text("Reply", cx)), + .tooltip(Tooltip::text("Reply")), ), ) }) @@ -628,7 +642,7 @@ impl ChatPanel { .id("edit") .child( IconButton::new(("edit", message_id), IconName::Pencil) - .on_click(cx.listener(move |this, _, cx| { + .on_click(cx.listener(move |this, _, window, cx| { this.message_editor.update(cx, |editor, cx| { editor.clear_reply_to_message_id(); @@ -655,18 +669,18 @@ impl ChatPanel { }); editor.set_edit_message_id(message_id); - editor.focus_handle(cx).focus(cx); + editor.focus_handle(cx).focus(window); } }) })), ) - .tooltip(|cx| Tooltip::text("Edit", cx)), + .tooltip(Tooltip::text("Edit")), ), ) }) }) .when_some(message_id, |el, message_id| { - let this = cx.view().clone(); + let this = cx.model().clone(); el.child( self.render_popover_button( @@ -678,34 +692,36 @@ impl ChatPanel { ("trigger", message_id), IconName::Ellipsis, )) - .menu(move |cx| { + .menu(move |window, cx| { Some(Self::render_message_menu( &this, message_id, can_delete_message, + window, cx, )) }), ) .id("more") - .tooltip(|cx| Tooltip::text("More", cx)), + .tooltip(Tooltip::text("More")), ), ) }) } fn render_message_menu( - this: &View, + this: &Entity, message_id: u64, can_delete_message: bool, - cx: &mut WindowContext, - ) -> View { + window: &mut Window, + cx: &mut App, + ) -> Entity { let menu = { - ContextMenu::build(cx, move |menu, cx| { + ContextMenu::build(window, cx, move |menu, window, _| { menu.entry( "Copy message text", None, - cx.handler_for(this, move |this, cx| { + window.handler_for(this, move |this, _, cx| { if let Some(message) = this.active_chat().and_then(|active_chat| { active_chat.read(cx).find_loaded_message(message_id) }) { @@ -718,15 +734,21 @@ impl ChatPanel { menu.entry( "Delete message", None, - cx.handler_for(this, move |this, cx| this.remove_message(message_id, cx)), + window.handler_for(this, move |this, _, cx| { + this.remove_message(message_id, cx) + }), ) }) }) }; this.update(cx, |this, cx| { - let subscription = cx.subscribe(&menu, |this: &mut Self, _, _: &DismissEvent, _| { - this.open_context_menu = None; - }); + let subscription = cx.subscribe_in( + &menu, + window, + |this: &mut Self, _, _: &DismissEvent, _, _| { + this.open_context_menu = None; + }, + ); this.open_context_menu = Some((message_id, subscription)); }); menu @@ -737,7 +759,7 @@ impl ChatPanel { current_user_id: u64, message: &channel::ChannelMessage, local_timezone: UtcOffset, - cx: &AppContext, + cx: &App, ) -> RichText { let mentions = message .mentions @@ -777,19 +799,19 @@ impl ChatPanel { ); rich_text.custom_ranges.push(range); - rich_text.set_tooltip_builder_for_custom_ranges(move |_, _, cx| { - Some(Tooltip::text(edit_timestamp_text.clone(), cx)) + rich_text.set_tooltip_builder_for_custom_ranges(move |_, _, _, cx| { + Some(Tooltip::simple(edit_timestamp_text.clone(), cx)) }) } } rich_text } - fn send(&mut self, _: &Confirm, cx: &mut ViewContext) { + fn send(&mut self, _: &Confirm, window: &mut Window, cx: &mut Context) { if let Some((chat, _)) = self.active_chat.as_ref() { let message = self .message_editor - .update(cx, |editor, cx| editor.take_message(cx)); + .update(cx, |editor, cx| editor.take_message(window, cx)); if let Some(id) = self.message_editor.read(cx).edit_message_id() { self.message_editor.update(cx, |editor, _| { @@ -811,13 +833,13 @@ impl ChatPanel { } } - fn remove_message(&mut self, id: u64, cx: &mut ViewContext) { + fn remove_message(&mut self, id: u64, cx: &mut Context) { if let Some((chat, _)) = self.active_chat.as_ref() { chat.update(cx, |chat, cx| chat.remove_message(id, cx).detach()) } } - fn load_more_messages(&mut self, cx: &mut ViewContext) { + fn load_more_messages(&mut self, cx: &mut Context) { if let Some((chat, _)) = self.active_chat.as_ref() { chat.update(cx, |channel, cx| { if let Some(task) = channel.load_more_messages(cx) { @@ -831,7 +853,7 @@ impl ChatPanel { &mut self, selected_channel_id: ChannelId, scroll_to_message_id: Option, - cx: &mut ViewContext, + cx: &mut Context, ) -> Task> { let open_chat = self .active_chat @@ -857,20 +879,18 @@ impl ChatPanel { if let Some(message_id) = scroll_to_message_id { if let Some(item_ix) = - ChannelChat::load_history_since_message(chat.clone(), message_id, (*cx).clone()) + ChannelChat::load_history_since_message(chat.clone(), message_id, cx.clone()) .await { this.update(&mut cx, |this, cx| { if let Some(highlight_message_id) = highlight_message_id { - let task = cx.spawn({ - |this, mut cx| async move { - cx.background_executor().timer(Duration::from_secs(2)).await; - this.update(&mut cx, |this, cx| { - this.highlighted_message.take(); - cx.notify(); - }) - .ok(); - } + let task = cx.spawn(|this, mut cx| async move { + cx.background_executor().timer(Duration::from_secs(2)).await; + this.update(&mut cx, |this, cx| { + this.highlighted_message.take(); + cx.notify(); + }) + .ok(); }); this.highlighted_message = Some((highlight_message_id, task)); @@ -891,12 +911,12 @@ impl ChatPanel { }) } - fn close_reply_preview(&mut self, cx: &mut ViewContext) { + fn close_reply_preview(&mut self, cx: &mut Context) { self.message_editor .update(cx, |editor, _| editor.clear_reply_to_message_id()); } - fn cancel_edit_message(&mut self, cx: &mut ViewContext) { + fn cancel_edit_message(&mut self, cx: &mut Context) { self.message_editor.update(cx, |editor, cx| { // only clear the editor input if we were editing a message if editor.edit_message_id().is_none() { @@ -919,7 +939,7 @@ impl ChatPanel { } impl Render for ChatPanel { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { let channel_id = self .active_chat .as_ref() @@ -971,11 +991,12 @@ impl Render for ChatPanel { .full_width() .key_binding(KeyBinding::for_action( &collab_panel::ToggleFocus, - cx, + window, )) - .on_click(|_, cx| { - cx.dispatch_action( + .on_click(|_, window, cx| { + window.dispatch_action( collab_panel::ToggleFocus.boxed_clone(), + cx, ) }), ), @@ -999,8 +1020,8 @@ impl Render for ChatPanel { .child( IconButton::new("cancel-edit-message", IconName::Close) .shape(ui::IconButtonShape::Square) - .tooltip(|cx| Tooltip::text("Cancel edit message", cx)) - .on_click(cx.listener(move |this, _, cx| { + .tooltip(Tooltip::text("Cancel edit message")) + .on_click(cx.listener(move |this, _, _, cx| { this.cancel_edit_message(cx); })), ), @@ -1045,7 +1066,7 @@ impl Render for ChatPanel { ) .when_some(channel_id, |this, channel_id| { this.cursor_pointer().on_click(cx.listener( - move |chat_panel, _, cx| { + move |chat_panel, _, _, cx| { chat_panel .select_channel( channel_id, @@ -1061,8 +1082,8 @@ impl Render for ChatPanel { .child( IconButton::new("close-reply-preview", IconName::Close) .shape(ui::IconButtonShape::Square) - .tooltip(|cx| Tooltip::text("Close reply", cx)) - .on_click(cx.listener(move |this, _, cx| { + .tooltip(Tooltip::text("Close reply")) + .on_click(cx.listener(move |this, _, _, cx| { this.close_reply_preview(cx); })), ), @@ -1073,7 +1094,7 @@ impl Render for ChatPanel { Some( h_flex() .p_2() - .on_action(cx.listener(|this, _: &actions::Cancel, cx| { + .on_action(cx.listener(|this, _: &actions::Cancel, _, cx| { this.cancel_edit_message(cx); this.close_reply_preview(cx); })) @@ -1085,8 +1106,8 @@ impl Render for ChatPanel { } } -impl FocusableView for ChatPanel { - fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle { +impl Focusable for ChatPanel { + fn focus_handle(&self, cx: &App) -> gpui::FocusHandle { if self.active_chat.is_some() { self.message_editor.read(cx).focus_handle(cx) } else { @@ -1096,7 +1117,7 @@ impl FocusableView for ChatPanel { } impl Panel for ChatPanel { - fn position(&self, cx: &WindowContext) -> DockPosition { + fn position(&self, _: &Window, cx: &App) -> DockPosition { ChatPanelSettings::get_global(cx).dock } @@ -1104,7 +1125,7 @@ impl Panel for ChatPanel { matches!(position, DockPosition::Left | DockPosition::Right) } - fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext) { + fn set_position(&mut self, position: DockPosition, _: &mut Window, cx: &mut Context) { settings::update_settings_file::( self.fs.clone(), cx, @@ -1112,18 +1133,18 @@ impl Panel for ChatPanel { ); } - fn size(&self, cx: &WindowContext) -> Pixels { + fn size(&self, _: &Window, cx: &App) -> Pixels { self.width .unwrap_or_else(|| ChatPanelSettings::get_global(cx).default_width) } - fn set_size(&mut self, size: Option, cx: &mut ViewContext) { + fn set_size(&mut self, size: Option, _: &mut Window, cx: &mut Context) { self.width = size; self.serialize(cx); cx.notify(); } - fn set_active(&mut self, active: bool, cx: &mut ViewContext) { + fn set_active(&mut self, active: bool, _: &mut Window, cx: &mut Context) { self.active = active; if active { self.acknowledge_last_message(cx); @@ -1134,7 +1155,7 @@ impl Panel for ChatPanel { "ChatPanel" } - fn icon(&self, cx: &WindowContext) -> Option { + fn icon(&self, _window: &Window, cx: &App) -> Option { let show_icon = match ChatPanelSettings::get_global(cx).button { ChatPanelButton::Never => false, ChatPanelButton::Always => true, @@ -1151,7 +1172,7 @@ impl Panel for ChatPanel { show_icon.then(|| ui::IconName::MessageBubbles) } - fn icon_tooltip(&self, _cx: &WindowContext) -> Option<&'static str> { + fn icon_tooltip(&self, _: &Window, _: &App) -> Option<&'static str> { Some("Chat Panel") } @@ -1159,7 +1180,7 @@ impl Panel for ChatPanel { Box::new(ToggleFocus) } - fn starts_open(&self, cx: &WindowContext) -> bool { + fn starts_open(&self, _: &Window, cx: &App) -> bool { ActiveCall::global(cx) .read(cx) .room() @@ -1183,7 +1204,7 @@ mod tests { use util::test::marked_text_ranges; #[gpui::test] - fn test_render_markdown_with_mentions(cx: &mut AppContext) { + fn test_render_markdown_with_mentions(cx: &mut App) { let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone())); let (body, ranges) = marked_text_ranges("*hi*, «@abc», let's **call** «@fgh»", false); let message = channel::ChannelMessage { @@ -1240,7 +1261,7 @@ mod tests { } #[gpui::test] - fn test_render_markdown_with_auto_detect_links(cx: &mut AppContext) { + fn test_render_markdown_with_auto_detect_links(cx: &mut App) { let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone())); let message = channel::ChannelMessage { id: ChannelMessageId::Saved(0), @@ -1289,7 +1310,7 @@ mod tests { } #[gpui::test] - fn test_render_markdown_with_auto_detect_links_and_additional_formatting(cx: &mut AppContext) { + fn test_render_markdown_with_auto_detect_links_and_additional_formatting(cx: &mut App) { let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone())); let message = channel::ChannelMessage { id: ChannelMessageId::Saved(0), diff --git a/crates/collab_ui/src/chat_panel/message_editor.rs b/crates/collab_ui/src/chat_panel/message_editor.rs index 7a05e6bce4..dcd1280ec3 100644 --- a/crates/collab_ui/src/chat_panel/message_editor.rs +++ b/crates/collab_ui/src/chat_panel/message_editor.rs @@ -1,12 +1,12 @@ -use anyhow::{Context, Result}; +use anyhow::{Context as _, Result}; use channel::{ChannelChat, ChannelStore, MessageParams}; use client::{UserId, UserStore}; use collections::HashSet; use editor::{AnchorRangeExt, CompletionProvider, Editor, EditorElement, EditorStyle}; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ - AsyncWindowContext, FocusableView, FontStyle, FontWeight, HighlightStyle, IntoElement, Model, - Render, Task, TextStyle, View, ViewContext, WeakView, + AsyncAppContext, AsyncWindowContext, Context, Entity, Focusable, FontStyle, FontWeight, + HighlightStyle, IntoElement, Render, Task, TextStyle, WeakEntity, Window, }; use language::{ language_settings::SoftWrap, Anchor, Buffer, BufferSnapshot, CodeLabel, LanguageRegistry, @@ -42,24 +42,25 @@ static MENTIONS_SEARCH: LazyLock = LazyLock::new(|| { }); pub struct MessageEditor { - pub editor: View, - user_store: Model, - channel_chat: Option>, + pub editor: Entity, + user_store: Entity, + channel_chat: Option>, mentions: Vec, mentions_task: Option>, reply_to_message_id: Option, edit_message_id: Option, } -struct MessageEditorCompletionProvider(WeakView); +struct MessageEditorCompletionProvider(WeakEntity); impl CompletionProvider for MessageEditorCompletionProvider { fn completions( &self, - buffer: &Model, + buffer: &Entity, buffer_position: language::Anchor, _: editor::CompletionContext, - cx: &mut ViewContext, + _window: &mut Window, + cx: &mut Context, ) -> Task>> { let Some(handle) = self.0.upgrade() else { return Task::ready(Ok(Vec::new())); @@ -71,21 +72,21 @@ impl CompletionProvider for MessageEditorCompletionProvider { fn resolve_completions( &self, - _buffer: Model, + _buffer: Entity, _completion_indices: Vec, _completions: Rc>>, - _cx: &mut ViewContext, + _cx: &mut Context, ) -> Task> { Task::ready(Ok(false)) } fn is_completion_trigger( &self, - _buffer: &Model, + _buffer: &Entity, _position: language::Anchor, text: &str, _trigger_in_words: bool, - _cx: &mut ViewContext, + _cx: &mut Context, ) -> bool { text == "@" } @@ -94,12 +95,13 @@ impl CompletionProvider for MessageEditorCompletionProvider { impl MessageEditor { pub fn new( language_registry: Arc, - user_store: Model, - channel_chat: Option>, - editor: View, - cx: &mut ViewContext, + user_store: Entity, + channel_chat: Option>, + editor: Entity, + window: &mut Window, + cx: &mut Context, ) -> Self { - let this = cx.view().downgrade(); + let this = cx.model().downgrade(); editor.update(cx, |editor, cx| { editor.set_soft_wrap_mode(SoftWrap::EditorWidth, cx); editor.set_use_autoclose(false); @@ -121,9 +123,10 @@ impl MessageEditor { .as_singleton() .expect("message editor must be singleton"); - cx.subscribe(&buffer, Self::on_buffer_event).detach(); - cx.observe_global::(|view, cx| { - view.editor.update(cx, |editor, cx| { + cx.subscribe_in(&buffer, window, Self::on_buffer_event) + .detach(); + cx.observe_global::(|this, cx| { + this.editor.update(cx, |editor, cx| { editor.set_auto_replace_emoji_shortcode( MessageEditorSettings::get_global(cx) .auto_replace_emoji_shortcode @@ -134,7 +137,7 @@ impl MessageEditor { .detach(); let markdown = language_registry.language_for_name("Markdown"); - cx.spawn(|_, mut cx| async move { + cx.spawn_in(window, |_, mut cx| async move { let markdown = markdown.await.context("failed to load Markdown language")?; buffer.update(&mut cx, |buffer, cx| { buffer.set_language(Some(markdown), cx) @@ -177,7 +180,7 @@ impl MessageEditor { self.edit_message_id = None; } - pub fn set_channel_chat(&mut self, chat: Model, cx: &mut ViewContext) { + pub fn set_channel_chat(&mut self, chat: Entity, cx: &mut Context) { let channel_id = chat.read(cx).channel_id; self.channel_chat = Some(chat); let channel_name = ChannelStore::global(cx) @@ -193,7 +196,7 @@ impl MessageEditor { }); } - pub fn take_message(&mut self, cx: &mut ViewContext) -> MessageParams { + pub fn take_message(&mut self, window: &mut Window, cx: &mut Context) -> MessageParams { self.editor.update(cx, |editor, cx| { let highlights = editor.text_highlights::(cx); let text = editor.text(cx); @@ -208,7 +211,7 @@ impl MessageEditor { Vec::new() }; - editor.clear(cx); + editor.clear(window, cx); self.mentions.clear(); let reply_to_message_id = std::mem::take(&mut self.reply_to_message_id); @@ -222,13 +225,14 @@ impl MessageEditor { fn on_buffer_event( &mut self, - buffer: Model, + buffer: &Entity, event: &language::BufferEvent, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if let language::BufferEvent::Reparsed | language::BufferEvent::Edited = event { let buffer = buffer.read(cx).snapshot(); - self.mentions_task = Some(cx.spawn(|this, cx| async move { + self.mentions_task = Some(cx.spawn_in(window, |this, cx| async move { cx.background_executor() .timer(MENTIONS_DEBOUNCE_INTERVAL) .await; @@ -239,9 +243,9 @@ impl MessageEditor { fn completions( &mut self, - buffer: &Model, + buffer: &Entity, end_anchor: Anchor, - cx: &mut ViewContext, + cx: &mut Context, ) -> Task>> { if let Some((start_anchor, query, candidates)) = self.collect_mention_candidates(buffer, end_anchor, cx) @@ -281,7 +285,7 @@ impl MessageEditor { } async fn resolve_completions_for_candidates( - cx: &AsyncWindowContext, + cx: &AsyncAppContext, query: &str, candidates: &[StringMatchCandidate], range: Range, @@ -336,9 +340,9 @@ impl MessageEditor { fn collect_mention_candidates( &mut self, - buffer: &Model, + buffer: &Entity, end_anchor: Anchor, - cx: &mut ViewContext, + cx: &mut Context, ) -> Option<(Anchor, String, Vec)> { let end_offset = end_anchor.to_offset(buffer.read(cx)); @@ -385,9 +389,9 @@ impl MessageEditor { fn collect_emoji_candidates( &mut self, - buffer: &Model, + buffer: &Entity, end_anchor: Anchor, - cx: &mut ViewContext, + cx: &mut Context, ) -> Option<(Anchor, String, &'static [StringMatchCandidate])> { static EMOJI_FUZZY_MATCH_CANDIDATES: LazyLock> = LazyLock::new(|| { @@ -445,7 +449,7 @@ impl MessageEditor { } async fn find_mentions( - this: WeakView, + this: WeakEntity, buffer: BufferSnapshot, mut cx: AsyncWindowContext, ) { @@ -499,13 +503,13 @@ impl MessageEditor { .ok(); } - pub(crate) fn focus_handle(&self, cx: &gpui::AppContext) -> gpui::FocusHandle { + pub(crate) fn focus_handle(&self, cx: &gpui::App) -> gpui::FocusHandle { self.editor.read(cx).focus_handle(cx) } } impl Render for MessageEditor { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { let settings = ThemeSettings::get_global(cx); let text_style = TextStyle { color: if self.editor.read(cx).read_only(cx) { diff --git a/crates/collab_ui/src/collab_panel.rs b/crates/collab_ui/src/collab_panel.rs index b9fa39ed96..555ba426cd 100644 --- a/crates/collab_ui/src/collab_panel.rs +++ b/crates/collab_ui/src/collab_panel.rs @@ -11,12 +11,11 @@ use db::kvp::KEY_VALUE_STORE; use editor::{Editor, EditorElement, EditorStyle}; use fuzzy::{match_strings, StringMatchCandidate}; use gpui::{ - actions, anchored, canvas, deferred, div, fill, list, point, prelude::*, px, AnyElement, - AppContext, AsyncWindowContext, Bounds, ClickEvent, ClipboardItem, DismissEvent, Div, - EventEmitter, FocusHandle, FocusableView, FontStyle, InteractiveElement, IntoElement, - ListOffset, ListState, Model, MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, - Render, SharedString, Styled, Subscription, Task, TextStyle, View, ViewContext, VisualContext, - WeakView, + actions, anchored, canvas, deferred, div, fill, list, point, prelude::*, px, AnyElement, App, + AsyncWindowContext, Bounds, ClickEvent, ClipboardItem, Context, DismissEvent, Div, Entity, + EventEmitter, FocusHandle, Focusable, FontStyle, InteractiveElement, IntoElement, ListOffset, + ListState, MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, Render, SharedString, + Styled, Subscription, Task, TextStyle, WeakEntity, Window, }; use menu::{Cancel, Confirm, SecondaryConfirm, SelectNext, SelectPrev}; use project::{Fs, Project}; @@ -62,21 +61,22 @@ struct ChannelMoveClipboard { const COLLABORATION_PANEL_KEY: &str = "CollaborationPanel"; -pub fn init(cx: &mut AppContext) { - cx.observe_new_views(|workspace: &mut Workspace, _| { - workspace.register_action(|workspace, _: &ToggleFocus, cx| { - workspace.toggle_panel_focus::(cx); +pub fn init(cx: &mut App) { + cx.observe_new(|workspace: &mut Workspace, _, _| { + workspace.register_action(|workspace, _: &ToggleFocus, window, cx| { + workspace.toggle_panel_focus::(window, cx); }); - workspace.register_action(|_, _: &OpenChannelNotes, cx| { + workspace.register_action(|_, _: &OpenChannelNotes, window, cx| { let channel_id = ActiveCall::global(cx) .read(cx) .room() .and_then(|room| room.read(cx).channel_id()); if let Some(channel_id) = channel_id { - let workspace = cx.view().clone(); - cx.window_context().defer(move |cx| { - ChannelView::open(channel_id, None, workspace, cx).detach_and_log_err(cx) + let workspace = cx.model().clone(); + window.defer(cx, move |window, cx| { + ChannelView::open(channel_id, None, workspace, window, cx) + .detach_and_log_err(cx) }); } }); @@ -111,22 +111,22 @@ pub struct CollabPanel { focus_handle: FocusHandle, channel_clipboard: Option, pending_serialization: Task>, - context_menu: Option<(View, Point, Subscription)>, + context_menu: Option<(Entity, Point, Subscription)>, list_state: ListState, - filter_editor: View, - channel_name_editor: View, + filter_editor: Entity, + channel_name_editor: Entity, channel_editing_state: Option, entries: Vec, selection: Option, - channel_store: Model, - user_store: Model, + channel_store: Entity, + user_store: Entity, client: Arc, - project: Model, + project: Entity, match_candidates: Vec, subscriptions: Vec, collapsed_sections: Vec
, collapsed_channels: Vec, - workspace: WeakView, + workspace: WeakEntity, } #[derive(Serialize, Deserialize)] @@ -190,10 +190,14 @@ enum ListEntry { } impl CollabPanel { - pub fn new(workspace: &mut Workspace, cx: &mut ViewContext) -> View { - cx.new_view(|cx| { - let filter_editor = cx.new_view(|cx| { - let mut editor = Editor::single_line(cx); + pub fn new( + workspace: &mut Workspace, + window: &mut Window, + cx: &mut Context, + ) -> Entity { + cx.new(|cx| { + let filter_editor = cx.new(|cx| { + let mut editor = Editor::single_line(window, cx); editor.set_placeholder_text("Filter...", cx); editor }); @@ -215,31 +219,39 @@ impl CollabPanel { }) .detach(); - let channel_name_editor = cx.new_view(Editor::single_line); + let channel_name_editor = cx.new(|cx| Editor::single_line(window, cx)); - cx.subscribe(&channel_name_editor, |this: &mut Self, _, event, cx| { - if let editor::EditorEvent::Blurred = event { - if let Some(state) = &this.channel_editing_state { - if state.pending_name().is_some() { - return; + cx.subscribe_in( + &channel_name_editor, + window, + |this: &mut Self, _, event, window, cx| { + if let editor::EditorEvent::Blurred = event { + if let Some(state) = &this.channel_editing_state { + if state.pending_name().is_some() { + return; + } } + this.take_editing_state(window, cx); + this.update_entries(false, cx); + cx.notify(); } - this.take_editing_state(cx); - this.update_entries(false, cx); - cx.notify(); - } - }) + }, + ) .detach(); - let view = cx.view().downgrade(); - let list_state = - ListState::new(0, gpui::ListAlignment::Top, px(1000.), move |ix, cx| { - if let Some(view) = view.upgrade() { - view.update(cx, |view, cx| view.render_list_entry(ix, cx)) + let model = cx.model().downgrade(); + let list_state = ListState::new( + 0, + gpui::ListAlignment::Top, + px(1000.), + move |ix, window, cx| { + if let Some(model) = model.upgrade() { + model.update(cx, |this, cx| this.render_list_entry(ix, window, cx)) } else { div().into_any() } - }); + }, + ); let mut this = Self { width: None, @@ -278,12 +290,13 @@ impl CollabPanel { })); this.subscriptions .push(cx.observe(&active_call, |this, _, cx| this.update_entries(true, cx))); - this.subscriptions.push(cx.subscribe( + this.subscriptions.push(cx.subscribe_in( &this.channel_store, - |this, _channel_store, e, cx| match e { + window, + |this, _channel_store, e, window, cx| match e { ChannelEvent::ChannelCreated(channel_id) | ChannelEvent::ChannelRenamed(channel_id) => { - if this.take_editing_state(cx) { + if this.take_editing_state(window, cx) { this.update_entries(false, cx); this.selection = this.entries.iter().position(|entry| { if let ListEntry::Channel { channel, .. } = entry { @@ -302,9 +315,9 @@ impl CollabPanel { } pub async fn load( - workspace: WeakView, + workspace: WeakEntity, mut cx: AsyncWindowContext, - ) -> anyhow::Result> { + ) -> anyhow::Result> { let serialized_panel = cx .background_executor() .spawn(async move { KEY_VALUE_STORE.read_kvp(COLLABORATION_PANEL_KEY) }) @@ -317,8 +330,8 @@ impl CollabPanel { .log_err() .flatten(); - workspace.update(&mut cx, |workspace, cx| { - let panel = CollabPanel::new(workspace, cx); + workspace.update_in(&mut cx, |workspace, window, cx| { + let panel = CollabPanel::new(workspace, window, cx); if let Some(serialized_panel) = serialized_panel { panel.update(cx, |panel, cx| { panel.width = serialized_panel.width.map(|w| w.round()); @@ -335,7 +348,7 @@ impl CollabPanel { }) } - fn serialize(&mut self, cx: &mut ViewContext) { + fn serialize(&mut self, cx: &mut Context) { let width = self.width; let collapsed_channels = self.collapsed_channels.clone(); self.pending_serialization = cx.background_executor().spawn( @@ -361,7 +374,7 @@ impl CollabPanel { self.list_state.scroll_to_reveal_item(ix) } - fn update_entries(&mut self, select_same_item: bool, cx: &mut ViewContext) { + fn update_entries(&mut self, select_same_item: bool, cx: &mut Context) { let channel_store = self.channel_store.read(cx); let user_store = self.user_store.read(cx); let query = self.filter_editor.read(cx).text(cx); @@ -799,7 +812,7 @@ impl CollabPanel { is_pending: bool, role: proto::ChannelRole, is_selected: bool, - cx: &mut ViewContext, + cx: &mut Context, ) -> ListItem { let user_id = user.id; let is_current_user = @@ -819,8 +832,8 @@ impl CollabPanel { } else if is_current_user { IconButton::new("leave-call", IconName::Exit) .style(ButtonStyle::Subtle) - .on_click(move |_, cx| Self::leave_call(cx)) - .tooltip(|cx| Tooltip::text("Leave Call", cx)) + .on_click(move |_, window, cx| Self::leave_call(window, cx)) + .tooltip(Tooltip::text("Leave Call")) .into_any_element() } else if role == proto::ChannelRole::Guest { Label::new("Guest").color(Color::Muted).into_any_element() @@ -835,20 +848,29 @@ impl CollabPanel { if role == proto::ChannelRole::Guest { return el; } - el.tooltip(move |cx| Tooltip::text(tooltip.clone(), cx)) - .on_click(cx.listener(move |this, _, cx| { + el.tooltip(Tooltip::text(tooltip.clone())) + .on_click(cx.listener(move |this, _, window, cx| { this.workspace - .update(cx, |workspace, cx| workspace.follow(peer_id, cx)) + .update(cx, |workspace, cx| workspace.follow(peer_id, window, cx)) .ok(); })) }) .when(is_call_admin, |el| { - el.on_secondary_mouse_down(cx.listener(move |this, event: &MouseDownEvent, cx| { - this.deploy_participant_context_menu(event.position, user_id, role, cx) - })) + el.on_secondary_mouse_down(cx.listener( + move |this, event: &MouseDownEvent, window, cx| { + this.deploy_participant_context_menu( + event.position, + user_id, + role, + window, + cx, + ) + }, + )) }) } + #[allow(clippy::too_many_arguments)] fn render_participant_project( &self, project_id: u64, @@ -856,7 +878,8 @@ impl CollabPanel { host_user_id: u64, is_last: bool, is_selected: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> impl IntoElement { let project_name: SharedString = if worktree_root_names.is_empty() { "untitled".to_string() @@ -867,23 +890,28 @@ impl CollabPanel { ListItem::new(project_id as usize) .toggle_state(is_selected) - .on_click(cx.listener(move |this, _, cx| { + .on_click(cx.listener(move |this, _, window, cx| { this.workspace .update(cx, |workspace, cx| { let app_state = workspace.app_state().clone(); workspace::join_in_room_project(project_id, host_user_id, app_state, cx) - .detach_and_prompt_err("Failed to join project", cx, |_, _| None); + .detach_and_prompt_err( + "Failed to join project", + window, + cx, + |_, _, _| None, + ); }) .ok(); })) .start_slot( h_flex() .gap_1() - .child(render_tree_branch(is_last, false, cx)) + .child(render_tree_branch(is_last, false, window, cx)) .child(IconButton::new(0, IconName::Folder)), ) .child(Label::new(project_name.clone())) - .tooltip(move |cx| Tooltip::text(format!("Open {}", project_name), cx)) + .tooltip(Tooltip::text(format!("Open {}", project_name))) } fn render_participant_screen( @@ -891,7 +919,8 @@ impl CollabPanel { peer_id: Option, is_last: bool, is_selected: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> impl IntoElement { let id = peer_id.map_or(usize::MAX, |id| id.as_u64() as usize); @@ -900,26 +929,26 @@ impl CollabPanel { .start_slot( h_flex() .gap_1() - .child(render_tree_branch(is_last, false, cx)) + .child(render_tree_branch(is_last, false, window, cx)) .child(IconButton::new(0, IconName::Screen)), ) .child(Label::new("Screen")) .when_some(peer_id, |this, _| { - this.on_click(cx.listener(move |this, _, cx| { + this.on_click(cx.listener(move |this, _, window, cx| { this.workspace .update(cx, |workspace, cx| { - workspace.open_shared_screen(peer_id.unwrap(), cx) + workspace.open_shared_screen(peer_id.unwrap(), window, cx) }) .ok(); })) - .tooltip(move |cx| Tooltip::text("Open shared screen", cx)) + .tooltip(Tooltip::text("Open shared screen")) }) } - fn take_editing_state(&mut self, cx: &mut ViewContext) -> bool { + fn take_editing_state(&mut self, window: &mut Window, cx: &mut Context) -> bool { if self.channel_editing_state.take().is_some() { self.channel_name_editor.update(cx, |editor, cx| { - editor.set_text("", cx); + editor.set_text("", window, cx); }); true } else { @@ -931,20 +960,21 @@ impl CollabPanel { &self, channel_id: ChannelId, is_selected: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> impl IntoElement { let channel_store = self.channel_store.read(cx); let has_channel_buffer_changed = channel_store.has_channel_buffer_changed(channel_id); ListItem::new("channel-notes") .toggle_state(is_selected) - .on_click(cx.listener(move |this, _, cx| { - this.open_channel_notes(channel_id, cx); + .on_click(cx.listener(move |this, _, window, cx| { + this.open_channel_notes(channel_id, window, cx); })) .start_slot( h_flex() .relative() .gap_1() - .child(render_tree_branch(false, true, cx)) + .child(render_tree_branch(false, true, window, cx)) .child(IconButton::new(0, IconName::File)) .children(has_channel_buffer_changed.then(|| { div() @@ -956,27 +986,28 @@ impl CollabPanel { })), ) .child(Label::new("notes")) - .tooltip(move |cx| Tooltip::text("Open Channel Notes", cx)) + .tooltip(Tooltip::text("Open Channel Notes")) } fn render_channel_chat( &self, channel_id: ChannelId, is_selected: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> impl IntoElement { let channel_store = self.channel_store.read(cx); let has_messages_notification = channel_store.has_new_messages(channel_id); ListItem::new("channel-chat") .toggle_state(is_selected) - .on_click(cx.listener(move |this, _, cx| { - this.join_channel_chat(channel_id, cx); + .on_click(cx.listener(move |this, _, window, cx| { + this.join_channel_chat(channel_id, window, cx); })) .start_slot( h_flex() .relative() .gap_1() - .child(render_tree_branch(false, false, cx)) + .child(render_tree_branch(false, false, window, cx)) .child(IconButton::new(0, IconName::MessageBubbles)) .children(has_messages_notification.then(|| { div() @@ -988,7 +1019,7 @@ impl CollabPanel { })), ) .child(Label::new("chat")) - .tooltip(move |cx| Tooltip::text("Open Chat", cx)) + .tooltip(Tooltip::text("Open Chat")) } fn has_subchannels(&self, ix: usize) -> bool { @@ -1006,9 +1037,10 @@ impl CollabPanel { position: Point, user_id: u64, role: proto::ChannelRole, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - let this = cx.view().clone(); + let this = cx.model().clone(); if !(role == proto::ChannelRole::Guest || role == proto::ChannelRole::Talker || role == proto::ChannelRole::Member) @@ -1016,12 +1048,12 @@ impl CollabPanel { return; } - let context_menu = ContextMenu::build(cx, |mut context_menu, cx| { + let context_menu = ContextMenu::build(window, cx, |mut context_menu, window, _| { if role == proto::ChannelRole::Guest { context_menu = context_menu.entry( "Grant Mic Access", None, - cx.handler_for(&this, move |_, cx| { + window.handler_for(&this, move |_, window, cx| { ActiveCall::global(cx) .update(cx, |call, cx| { let Some(room) = call.room() else { @@ -1035,7 +1067,12 @@ impl CollabPanel { ) }) }) - .detach_and_prompt_err("Failed to grant mic access", cx, |_, _| None) + .detach_and_prompt_err( + "Failed to grant mic access", + window, + cx, + |_, _, _| None, + ) }), ); } @@ -1043,7 +1080,7 @@ impl CollabPanel { context_menu = context_menu.entry( "Grant Write Access", None, - cx.handler_for(&this, move |_, cx| { + window.handler_for(&this, move |_, window, cx| { ActiveCall::global(cx) .update(cx, |call, cx| { let Some(room) = call.room() else { @@ -1057,7 +1094,7 @@ impl CollabPanel { ) }) }) - .detach_and_prompt_err("Failed to grant write access", cx, |e, _| { + .detach_and_prompt_err("Failed to grant write access", window, cx, |e, _, _| { match e.error_code() { ErrorCode::NeedsCla => Some("This user has not yet signed the CLA at https://zed.dev/cla.".into()), _ => None, @@ -1075,7 +1112,7 @@ impl CollabPanel { context_menu = context_menu.entry( label, None, - cx.handler_for(&this, move |_, cx| { + window.handler_for(&this, move |_, window, cx| { ActiveCall::global(cx) .update(cx, |call, cx| { let Some(room) = call.room() else { @@ -1089,7 +1126,12 @@ impl CollabPanel { ) }) }) - .detach_and_prompt_err("Failed to revoke access", cx, |_, _| None) + .detach_and_prompt_err( + "Failed to revoke access", + window, + cx, + |_, _, _| None, + ) }), ); } @@ -1097,17 +1139,20 @@ impl CollabPanel { context_menu }); - cx.focus_view(&context_menu); - let subscription = - cx.subscribe(&context_menu, |this, _, _: &DismissEvent, cx| { + window.focus(&context_menu.focus_handle(cx)); + let subscription = cx.subscribe_in( + &context_menu, + window, + |this, _, _: &DismissEvent, window, cx| { if this.context_menu.as_ref().is_some_and(|context_menu| { - context_menu.0.focus_handle(cx).contains_focused(cx) + context_menu.0.focus_handle(cx).contains_focused(window, cx) }) { - cx.focus_self(); + cx.focus_self(window); } this.context_menu.take(); cx.notify(); - }); + }, + ); self.context_menu = Some((context_menu, position, subscription)); } @@ -1116,7 +1161,8 @@ impl CollabPanel { position: Point, channel_id: ChannelId, ix: usize, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let clipboard_channel_name = self.channel_clipboard.as_ref().and_then(|clipboard| { self.channel_store @@ -1124,9 +1170,9 @@ impl CollabPanel { .channel_for_id(clipboard.channel_id) .map(|channel| channel.name.clone()) }); - let this = cx.view().clone(); + let this = cx.model().clone(); - let context_menu = ContextMenu::build(cx, |mut context_menu, cx| { + let context_menu = ContextMenu::build(window, cx, |mut context_menu, window, cx| { if self.has_subchannels(ix) { let expand_action_name = if self.is_channel_collapsed(channel_id) { "Expand Subchannels" @@ -1136,8 +1182,8 @@ impl CollabPanel { context_menu = context_menu.entry( expand_action_name, None, - cx.handler_for(&this, move |this, cx| { - this.toggle_channel_collapsed(channel_id, cx) + window.handler_for(&this, move |this, window, cx| { + this.toggle_channel_collapsed(channel_id, window, cx) }), ); } @@ -1146,21 +1192,21 @@ impl CollabPanel { .entry( "Open Notes", None, - cx.handler_for(&this, move |this, cx| { - this.open_channel_notes(channel_id, cx) + window.handler_for(&this, move |this, window, cx| { + this.open_channel_notes(channel_id, window, cx) }), ) .entry( "Open Chat", None, - cx.handler_for(&this, move |this, cx| { - this.join_channel_chat(channel_id, cx) + window.handler_for(&this, move |this, window, cx| { + this.join_channel_chat(channel_id, window, cx) }), ) .entry( "Copy Channel Link", None, - cx.handler_for(&this, move |this, cx| { + window.handler_for(&this, move |this, _, cx| { this.copy_channel_link(channel_id, cx) }), ); @@ -1173,20 +1219,24 @@ impl CollabPanel { .entry( "New Subchannel", None, - cx.handler_for(&this, move |this, cx| this.new_subchannel(channel_id, cx)), + window.handler_for(&this, move |this, window, cx| { + this.new_subchannel(channel_id, window, cx) + }), ) .entry( "Rename", Some(Box::new(SecondaryConfirm)), - cx.handler_for(&this, move |this, cx| this.rename_channel(channel_id, cx)), + window.handler_for(&this, move |this, window, cx| { + this.rename_channel(channel_id, window, cx) + }), ); if let Some(channel_name) = clipboard_channel_name { context_menu = context_menu.separator().entry( format!("Move '#{}' here", channel_name), None, - cx.handler_for(&this, move |this, cx| { - this.move_channel_on_clipboard(channel_id, cx) + window.handler_for(&this, move |this, window, cx| { + this.move_channel_on_clipboard(channel_id, window, cx) }), ); } @@ -1195,24 +1245,27 @@ impl CollabPanel { context_menu = context_menu.separator().entry( "Manage Members", None, - cx.handler_for(&this, move |this, cx| this.manage_members(channel_id, cx)), + window.handler_for(&this, move |this, window, cx| { + this.manage_members(channel_id, window, cx) + }), ) } else { context_menu = context_menu.entry( "Move this channel", None, - cx.handler_for(&this, move |this, cx| { - this.start_move_channel(channel_id, cx) + window.handler_for(&this, move |this, window, cx| { + this.start_move_channel(channel_id, window, cx) }), ); if self.channel_store.read(cx).is_public_channel(channel_id) { context_menu = context_menu.separator().entry( "Make Channel Private", None, - cx.handler_for(&this, move |this, cx| { + window.handler_for(&this, move |this, window, cx| { this.set_channel_visibility( channel_id, ChannelVisibility::Members, + window, cx, ) }), @@ -1221,10 +1274,11 @@ impl CollabPanel { context_menu = context_menu.separator().entry( "Make Channel Public", None, - cx.handler_for(&this, move |this, cx| { + window.handler_for(&this, move |this, window, cx| { this.set_channel_visibility( channel_id, ChannelVisibility::Public, + window, cx, ) }), @@ -1235,7 +1289,9 @@ impl CollabPanel { context_menu = context_menu.entry( "Delete", None, - cx.handler_for(&this, move |this, cx| this.remove_channel(channel_id, cx)), + window.handler_for(&this, move |this, window, cx| { + this.remove_channel(channel_id, window, cx) + }), ); } @@ -1246,24 +1302,29 @@ impl CollabPanel { context_menu = context_menu.entry( "Leave Channel", None, - cx.handler_for(&this, move |this, cx| this.leave_channel(channel_id, cx)), + window.handler_for(&this, move |this, window, cx| { + this.leave_channel(channel_id, window, cx) + }), ); } context_menu }); - cx.focus_view(&context_menu); - let subscription = - cx.subscribe(&context_menu, |this, _, _: &DismissEvent, cx| { + window.focus(&context_menu.focus_handle(cx)); + let subscription = cx.subscribe_in( + &context_menu, + window, + |this, _, _: &DismissEvent, window, cx| { if this.context_menu.as_ref().is_some_and(|context_menu| { - context_menu.0.focus_handle(cx).contains_focused(cx) + context_menu.0.focus_handle(cx).contains_focused(window, cx) }) { - cx.focus_self(); + cx.focus_self(window); } this.context_menu.take(); cx.notify(); - }); + }, + ); self.context_menu = Some((context_menu, position, subscription)); cx.notify(); @@ -1273,12 +1334,13 @@ impl CollabPanel { &mut self, position: Point, contact: Arc, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - let this = cx.view().clone(); + let this = cx.model().clone(); let in_room = ActiveCall::global(cx).read(cx).room().is_some(); - let context_menu = ContextMenu::build(cx, |mut context_menu, _| { + let context_menu = ContextMenu::build(window, cx, |mut context_menu, _, _| { let user_id = contact.user.id; if contact.online && !contact.busy { @@ -1289,9 +1351,9 @@ impl CollabPanel { }; context_menu = context_menu.entry(label, None, { let this = this.clone(); - move |cx| { + move |window, cx| { this.update(cx, |this, cx| { - this.call(user_id, cx); + this.call(user_id, window, cx); }); } }); @@ -1299,34 +1361,42 @@ impl CollabPanel { context_menu.entry("Remove Contact", None, { let this = this.clone(); - move |cx| { + move |window, cx| { this.update(cx, |this, cx| { - this.remove_contact(contact.user.id, &contact.user.github_login, cx); + this.remove_contact( + contact.user.id, + &contact.user.github_login, + window, + cx, + ); }); } }) }); - cx.focus_view(&context_menu); - let subscription = - cx.subscribe(&context_menu, |this, _, _: &DismissEvent, cx| { + window.focus(&context_menu.focus_handle(cx)); + let subscription = cx.subscribe_in( + &context_menu, + window, + |this, _, _: &DismissEvent, window, cx| { if this.context_menu.as_ref().is_some_and(|context_menu| { - context_menu.0.focus_handle(cx).contains_focused(cx) + context_menu.0.focus_handle(cx).contains_focused(window, cx) }) { - cx.focus_self(); + cx.focus_self(window); } this.context_menu.take(); cx.notify(); - }); + }, + ); self.context_menu = Some((context_menu, position, subscription)); cx.notify(); } - fn reset_filter_editor_text(&mut self, cx: &mut ViewContext) -> bool { + fn reset_filter_editor_text(&mut self, window: &mut Window, cx: &mut Context) -> bool { self.filter_editor.update(cx, |editor, cx| { if editor.buffer().read(cx).len(cx) > 0 { - editor.set_text("", cx); + editor.set_text("", window, cx); true } else { false @@ -1334,11 +1404,11 @@ impl CollabPanel { }) } - fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext) { - if self.take_editing_state(cx) { - cx.focus_view(&self.filter_editor); - } else if !self.reset_filter_editor_text(cx) { - self.focus_handle.focus(cx); + fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context) { + if self.take_editing_state(window, cx) { + window.focus(&self.filter_editor.focus_handle(cx)); + } else if !self.reset_filter_editor_text(window, cx) { + self.focus_handle.focus(window); } if self.context_menu.is_some() { @@ -1349,7 +1419,7 @@ impl CollabPanel { self.update_entries(false, cx); } - fn select_next(&mut self, _: &SelectNext, cx: &mut ViewContext) { + fn select_next(&mut self, _: &SelectNext, _: &mut Window, cx: &mut Context) { let ix = self.selection.map_or(0, |ix| ix + 1); if ix < self.entries.len() { self.selection = Some(ix); @@ -1361,7 +1431,7 @@ impl CollabPanel { cx.notify(); } - fn select_prev(&mut self, _: &SelectPrev, cx: &mut ViewContext) { + fn select_prev(&mut self, _: &SelectPrev, _: &mut Window, cx: &mut Context) { let ix = self.selection.take().unwrap_or(0); if ix > 0 { self.selection = Some(ix - 1); @@ -1373,8 +1443,8 @@ impl CollabPanel { cx.notify(); } - fn confirm(&mut self, _: &Confirm, cx: &mut ViewContext) { - if self.confirm_channel_edit(cx) { + fn confirm(&mut self, _: &Confirm, window: &mut Window, cx: &mut Context) { + if self.confirm_channel_edit(window, cx) { return; } @@ -1382,9 +1452,9 @@ impl CollabPanel { if let Some(entry) = self.entries.get(selection) { match entry { ListEntry::Header(section) => match section { - Section::ActiveCall => Self::leave_call(cx), - Section::Channels => self.new_root_channel(cx), - Section::Contacts => self.toggle_contact_finder(cx), + Section::ActiveCall => Self::leave_call(window, cx), + Section::Channels => self.new_root_channel(window, cx), + Section::Contacts => self.toggle_contact_finder(window, cx), Section::ContactRequests | Section::Online | Section::Offline @@ -1394,7 +1464,7 @@ impl CollabPanel { }, ListEntry::Contact { contact, calling } => { if contact.online && !contact.busy && !calling { - self.call(contact.user.id, cx); + self.call(contact.user.id, window, cx); } } ListEntry::ParticipantProject { @@ -1412,8 +1482,9 @@ impl CollabPanel { ) .detach_and_prompt_err( "Failed to join project", + window, cx, - |_, _| None, + |_, _, _| None, ); } } @@ -1423,7 +1494,7 @@ impl CollabPanel { }; if let Some(workspace) = self.workspace.upgrade() { workspace.update(cx, |workspace, cx| { - workspace.open_shared_screen(*peer_id, cx) + workspace.open_shared_screen(*peer_id, window, cx) }); } } @@ -1439,32 +1510,32 @@ impl CollabPanel { }) .unwrap_or(false); if is_active { - self.open_channel_notes(channel.id, cx) + self.open_channel_notes(channel.id, window, cx) } else { - self.join_channel(channel.id, cx) + self.join_channel(channel.id, window, cx) } } - ListEntry::ContactPlaceholder => self.toggle_contact_finder(cx), + ListEntry::ContactPlaceholder => self.toggle_contact_finder(window, cx), ListEntry::CallParticipant { user, peer_id, .. } => { if Some(user) == self.user_store.read(cx).current_user().as_ref() { - Self::leave_call(cx); + Self::leave_call(window, cx); } else if let Some(peer_id) = peer_id { self.workspace - .update(cx, |workspace, cx| workspace.follow(*peer_id, cx)) + .update(cx, |workspace, cx| workspace.follow(*peer_id, window, cx)) .ok(); } } ListEntry::IncomingRequest(user) => { - self.respond_to_contact_request(user.id, true, cx) + self.respond_to_contact_request(user.id, true, window, cx) } ListEntry::ChannelInvite(channel) => { self.respond_to_channel_invite(channel.id, true, cx) } ListEntry::ChannelNotes { channel_id } => { - self.open_channel_notes(*channel_id, cx) + self.open_channel_notes(*channel_id, window, cx) } ListEntry::ChannelChat { channel_id } => { - self.join_channel_chat(*channel_id, cx) + self.join_channel_chat(*channel_id, window, cx) } ListEntry::OutgoingRequest(_) => {} ListEntry::ChannelEditor { .. } => {} @@ -1473,15 +1544,15 @@ impl CollabPanel { } } - fn insert_space(&mut self, _: &InsertSpace, cx: &mut ViewContext) { + fn insert_space(&mut self, _: &InsertSpace, window: &mut Window, cx: &mut Context) { if self.channel_editing_state.is_some() { self.channel_name_editor.update(cx, |editor, cx| { - editor.insert(" ", cx); + editor.insert(" ", window, cx); }); } } - fn confirm_channel_edit(&mut self, cx: &mut ViewContext) -> bool { + fn confirm_channel_edit(&mut self, window: &mut Window, cx: &mut Context) -> bool { if let Some(editing_state) = &mut self.channel_editing_state { match editing_state { ChannelEditingState::Create { @@ -1500,23 +1571,30 @@ impl CollabPanel { channel_store.create_channel(&channel_name, *location, cx) }); if location.is_none() { - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { let channel_id = create.await?; - this.update(&mut cx, |this, cx| { + this.update_in(&mut cx, |this, window, cx| { this.show_channel_modal( channel_id, channel_modal::Mode::InviteMembers, + window, cx, ) }) }) .detach_and_prompt_err( "Failed to create channel", + window, cx, - |_, _| None, + |_, _, _| None, ); } else { - create.detach_and_prompt_err("Failed to create channel", cx, |_, _| None); + create.detach_and_prompt_err( + "Failed to create channel", + window, + cx, + |_, _, _| None, + ); } cx.notify(); } @@ -1538,14 +1616,14 @@ impl CollabPanel { cx.notify(); } } - cx.focus_self(); + cx.focus_self(window); true } else { false } } - fn toggle_section_expanded(&mut self, section: Section, cx: &mut ViewContext) { + fn toggle_section_expanded(&mut self, section: Section, cx: &mut Context) { if let Some(ix) = self.collapsed_sections.iter().position(|s| *s == section) { self.collapsed_sections.remove(ix); } else { @@ -1557,7 +1635,8 @@ impl CollabPanel { fn collapse_selected_channel( &mut self, _: &CollapseSelectedChannel, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let Some(channel_id) = self.selected_channel().map(|channel| channel.id) else { return; @@ -1567,10 +1646,15 @@ impl CollabPanel { return; } - self.toggle_channel_collapsed(channel_id, cx); + self.toggle_channel_collapsed(channel_id, window, cx); } - fn expand_selected_channel(&mut self, _: &ExpandSelectedChannel, cx: &mut ViewContext) { + fn expand_selected_channel( + &mut self, + _: &ExpandSelectedChannel, + window: &mut Window, + cx: &mut Context, + ) { let Some(id) = self.selected_channel().map(|channel| channel.id) else { return; }; @@ -1579,10 +1663,15 @@ impl CollabPanel { return; } - self.toggle_channel_collapsed(id, cx) + self.toggle_channel_collapsed(id, window, cx) } - fn toggle_channel_collapsed(&mut self, channel_id: ChannelId, cx: &mut ViewContext) { + fn toggle_channel_collapsed( + &mut self, + channel_id: ChannelId, + window: &mut Window, + cx: &mut Context, + ) { match self.collapsed_channels.binary_search(&channel_id) { Ok(ix) => { self.collapsed_channels.remove(ix); @@ -1594,39 +1683,39 @@ impl CollabPanel { self.serialize(cx); self.update_entries(true, cx); cx.notify(); - cx.focus_self(); + cx.focus_self(window); } fn is_channel_collapsed(&self, channel_id: ChannelId) -> bool { self.collapsed_channels.binary_search(&channel_id).is_ok() } - fn leave_call(cx: &mut WindowContext) { + fn leave_call(window: &mut Window, cx: &mut App) { ActiveCall::global(cx) .update(cx, |call, cx| call.hang_up(cx)) - .detach_and_prompt_err("Failed to hang up", cx, |_, _| None); + .detach_and_prompt_err("Failed to hang up", window, cx, |_, _, _| None); } - fn toggle_contact_finder(&mut self, cx: &mut ViewContext) { + fn toggle_contact_finder(&mut self, window: &mut Window, cx: &mut Context) { if let Some(workspace) = self.workspace.upgrade() { workspace.update(cx, |workspace, cx| { - workspace.toggle_modal(cx, |cx| { - let mut finder = ContactFinder::new(self.user_store.clone(), cx); - finder.set_query(self.filter_editor.read(cx).text(cx), cx); + workspace.toggle_modal(window, cx, |window, cx| { + let mut finder = ContactFinder::new(self.user_store.clone(), window, cx); + finder.set_query(self.filter_editor.read(cx).text(cx), window, cx); finder }); }); } } - fn new_root_channel(&mut self, cx: &mut ViewContext) { + fn new_root_channel(&mut self, window: &mut Window, cx: &mut Context) { self.channel_editing_state = Some(ChannelEditingState::Create { location: None, pending_name: None, }); self.update_entries(false, cx); self.select_channel_editor(); - cx.focus_view(&self.channel_name_editor); + window.focus(&self.channel_name_editor.focus_handle(cx)); cx.notify(); } @@ -1637,7 +1726,12 @@ impl CollabPanel { }); } - fn new_subchannel(&mut self, channel_id: ChannelId, cx: &mut ViewContext) { + fn new_subchannel( + &mut self, + channel_id: ChannelId, + window: &mut Window, + cx: &mut Context, + ) { self.collapsed_channels .retain(|channel| *channel != channel_id); self.channel_editing_state = Some(ChannelEditingState::Create { @@ -1646,27 +1740,42 @@ impl CollabPanel { }); self.update_entries(false, cx); self.select_channel_editor(); - cx.focus_view(&self.channel_name_editor); + window.focus(&self.channel_name_editor.focus_handle(cx)); cx.notify(); } - fn manage_members(&mut self, channel_id: ChannelId, cx: &mut ViewContext) { - self.show_channel_modal(channel_id, channel_modal::Mode::ManageMembers, cx); + fn manage_members( + &mut self, + channel_id: ChannelId, + window: &mut Window, + cx: &mut Context, + ) { + self.show_channel_modal(channel_id, channel_modal::Mode::ManageMembers, window, cx); } - fn remove_selected_channel(&mut self, _: &Remove, cx: &mut ViewContext) { + fn remove_selected_channel(&mut self, _: &Remove, window: &mut Window, cx: &mut Context) { if let Some(channel) = self.selected_channel() { - self.remove_channel(channel.id, cx) + self.remove_channel(channel.id, window, cx) } } - fn rename_selected_channel(&mut self, _: &SecondaryConfirm, cx: &mut ViewContext) { + fn rename_selected_channel( + &mut self, + _: &SecondaryConfirm, + window: &mut Window, + cx: &mut Context, + ) { if let Some(channel) = self.selected_channel() { - self.rename_channel(channel.id, cx); + self.rename_channel(channel.id, window, cx); } } - fn rename_channel(&mut self, channel_id: ChannelId, cx: &mut ViewContext) { + fn rename_channel( + &mut self, + channel_id: ChannelId, + window: &mut Window, + cx: &mut Context, + ) { let channel_store = self.channel_store.read(cx); if !channel_store.is_channel_admin(channel_id) { return; @@ -1677,10 +1786,10 @@ impl CollabPanel { pending_name: None, }); self.channel_name_editor.update(cx, |editor, cx| { - editor.set_text(channel.name.clone(), cx); - editor.select_all(&Default::default(), cx); + editor.set_text(channel.name.clone(), window, cx); + editor.select_all(&Default::default(), window, cx); }); - cx.focus_view(&self.channel_name_editor); + window.focus(&self.channel_name_editor.focus_handle(cx)); self.update_entries(false, cx); self.select_channel_editor(); } @@ -1690,13 +1799,14 @@ impl CollabPanel { &mut self, channel_id: ChannelId, visibility: ChannelVisibility, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { self.channel_store .update(cx, |channel_store, cx| { channel_store.set_channel_visibility(channel_id, visibility, cx) }) - .detach_and_prompt_err("Failed to set channel visibility", cx, |e, _| match e.error_code() { + .detach_and_prompt_err("Failed to set channel visibility", window, cx, |e, _, _| match e.error_code() { ErrorCode::BadPublicNesting => if e.error_tag("direction") == Some("parent") { Some("To make a channel public, its parent channel must be public.".to_string()) @@ -1707,50 +1817,81 @@ impl CollabPanel { }); } - fn start_move_channel(&mut self, channel_id: ChannelId, _cx: &mut ViewContext) { + fn start_move_channel( + &mut self, + channel_id: ChannelId, + _window: &mut Window, + _cx: &mut Context, + ) { self.channel_clipboard = Some(ChannelMoveClipboard { channel_id }); } - fn start_move_selected_channel(&mut self, _: &StartMoveChannel, cx: &mut ViewContext) { + fn start_move_selected_channel( + &mut self, + _: &StartMoveChannel, + window: &mut Window, + cx: &mut Context, + ) { if let Some(channel) = self.selected_channel() { - self.start_move_channel(channel.id, cx); + self.start_move_channel(channel.id, window, cx); } } fn move_channel_on_clipboard( &mut self, to_channel_id: ChannelId, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if let Some(clipboard) = self.channel_clipboard.take() { - self.move_channel(clipboard.channel_id, to_channel_id, cx) + self.move_channel(clipboard.channel_id, to_channel_id, window, cx) } } - fn move_channel(&self, channel_id: ChannelId, to: ChannelId, cx: &mut ViewContext) { + fn move_channel( + &self, + channel_id: ChannelId, + to: ChannelId, + window: &mut Window, + cx: &mut Context, + ) { self.channel_store .update(cx, |channel_store, cx| { channel_store.move_channel(channel_id, to, cx) }) - .detach_and_prompt_err("Failed to move channel", cx, |e, _| match e.error_code() { - ErrorCode::BadPublicNesting => { - Some("Public channels must have public parents".into()) + .detach_and_prompt_err("Failed to move channel", window, cx, |e, _, _| { + match e.error_code() { + ErrorCode::BadPublicNesting => { + Some("Public channels must have public parents".into()) + } + ErrorCode::CircularNesting => { + Some("You cannot move a channel into itself".into()) + } + ErrorCode::WrongMoveTarget => { + Some("You cannot move a channel into a different root channel".into()) + } + _ => None, } - ErrorCode::CircularNesting => Some("You cannot move a channel into itself".into()), - ErrorCode::WrongMoveTarget => { - Some("You cannot move a channel into a different root channel".into()) - } - _ => None, }) } - fn open_channel_notes(&mut self, channel_id: ChannelId, cx: &mut ViewContext) { + fn open_channel_notes( + &mut self, + channel_id: ChannelId, + window: &mut Window, + cx: &mut Context, + ) { if let Some(workspace) = self.workspace.upgrade() { - ChannelView::open(channel_id, None, workspace, cx).detach(); + ChannelView::open(channel_id, None, workspace, window, cx).detach(); } } - fn show_inline_context_menu(&mut self, _: &menu::SecondaryConfirm, cx: &mut ViewContext) { + fn show_inline_context_menu( + &mut self, + _: &menu::SecondaryConfirm, + window: &mut Window, + cx: &mut Context, + ) { let Some(bounds) = self .selection .and_then(|ix| self.list_state.bounds_for_item(ix)) @@ -1763,6 +1904,7 @@ impl CollabPanel { bounds.center(), channel.id, self.selection.unwrap(), + window, cx, ); cx.stop_propagation(); @@ -1770,7 +1912,7 @@ impl CollabPanel { }; if let Some(contact) = self.selected_contact() { - self.deploy_contact_context_menu(bounds.center(), contact, cx); + self.deploy_contact_context_menu(bounds.center(), contact, window, cx); cx.stop_propagation(); } } @@ -1797,20 +1939,22 @@ impl CollabPanel { &mut self, channel_id: ChannelId, mode: channel_modal::Mode, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let workspace = self.workspace.clone(); let user_store = self.user_store.clone(); let channel_store = self.channel_store.clone(); - cx.spawn(|_, mut cx| async move { - workspace.update(&mut cx, |workspace, cx| { - workspace.toggle_modal(cx, |cx| { + cx.spawn_in(window, |_, mut cx| async move { + workspace.update_in(&mut cx, |workspace, window, cx| { + workspace.toggle_modal(window, cx, |window, cx| { ChannelModal::new( user_store.clone(), channel_store.clone(), channel_id, mode, + window, cx, ) }); @@ -1819,7 +1963,7 @@ impl CollabPanel { .detach(); } - fn leave_channel(&self, channel_id: ChannelId, cx: &mut ViewContext) { + fn leave_channel(&self, channel_id: ChannelId, window: &mut Window, cx: &mut Context) { let Some(user_id) = self.user_store.read(cx).current_user().map(|u| u.id) else { return; }; @@ -1827,13 +1971,14 @@ impl CollabPanel { return; }; let prompt_message = format!("Are you sure you want to leave \"#{}\"?", channel.name); - let answer = cx.prompt( + let answer = window.prompt( PromptLevel::Warning, &prompt_message, None, &["Leave", "Cancel"], + cx, ); - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { if answer.await? != 0 { return Ok(()); } @@ -1844,29 +1989,36 @@ impl CollabPanel { })? .await }) - .detach_and_prompt_err("Failed to leave channel", cx, |_, _| None) + .detach_and_prompt_err("Failed to leave channel", window, cx, |_, _, _| None) } - fn remove_channel(&mut self, channel_id: ChannelId, cx: &mut ViewContext) { + fn remove_channel( + &mut self, + channel_id: ChannelId, + window: &mut Window, + cx: &mut Context, + ) { let channel_store = self.channel_store.clone(); if let Some(channel) = channel_store.read(cx).channel_for_id(channel_id) { let prompt_message = format!( "Are you sure you want to remove the channel \"{}\"?", channel.name ); - let answer = cx.prompt( + let answer = window.prompt( PromptLevel::Warning, &prompt_message, None, &["Remove", "Cancel"], + cx, ); - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { if answer.await? == 0 { channel_store .update(&mut cx, |channels, _| channels.remove_channel(channel_id))? .await .notify_async_err(&mut cx); - this.update(&mut cx, |_, cx| cx.focus_self()).ok(); + this.update_in(&mut cx, |_, window, cx| cx.focus_self(window)) + .ok(); } anyhow::Ok(()) }) @@ -1874,19 +2026,26 @@ impl CollabPanel { } } - fn remove_contact(&mut self, user_id: u64, github_login: &str, cx: &mut ViewContext) { + fn remove_contact( + &mut self, + user_id: u64, + github_login: &str, + window: &mut Window, + cx: &mut Context, + ) { let user_store = self.user_store.clone(); let prompt_message = format!( "Are you sure you want to remove \"{}\" from your contacts?", github_login ); - let answer = cx.prompt( + let answer = window.prompt( PromptLevel::Warning, &prompt_message, None, &["Remove", "Cancel"], + cx, ); - cx.spawn(|_, mut cx| async move { + cx.spawn_in(window, |_, mut cx| async move { if answer.await? == 0 { user_store .update(&mut cx, |store, cx| store.remove_contact(user_id, cx))? @@ -1895,27 +2054,33 @@ impl CollabPanel { } anyhow::Ok(()) }) - .detach_and_prompt_err("Failed to remove contact", cx, |_, _| None); + .detach_and_prompt_err("Failed to remove contact", window, cx, |_, _, _| None); } fn respond_to_contact_request( &mut self, user_id: u64, accept: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { self.user_store .update(cx, |store, cx| { store.respond_to_contact_request(user_id, accept, cx) }) - .detach_and_prompt_err("Failed to respond to contact request", cx, |_, _| None); + .detach_and_prompt_err( + "Failed to respond to contact request", + window, + cx, + |_, _, _| None, + ); } fn respond_to_channel_invite( &mut self, channel_id: ChannelId, accept: bool, - cx: &mut ViewContext, + cx: &mut Context, ) { self.channel_store .update(cx, |store, cx| { @@ -1924,19 +2089,19 @@ impl CollabPanel { .detach(); } - fn call(&mut self, recipient_user_id: u64, cx: &mut ViewContext) { + fn call(&mut self, recipient_user_id: u64, window: &mut Window, cx: &mut Context) { ActiveCall::global(cx) .update(cx, |call, cx| { call.invite(recipient_user_id, Some(self.project.clone()), cx) }) - .detach_and_prompt_err("Call failed", cx, |_, _| None); + .detach_and_prompt_err("Call failed", window, cx, |_, _, _| None); } - fn join_channel(&self, channel_id: ChannelId, cx: &mut ViewContext) { + fn join_channel(&self, channel_id: ChannelId, window: &mut Window, cx: &mut Context) { let Some(workspace) = self.workspace.upgrade() else { return; }; - let Some(handle) = cx.window_handle().downcast::() else { + let Some(handle) = window.window_handle().downcast::() else { return; }; workspace::join_channel( @@ -1945,27 +2110,32 @@ impl CollabPanel { Some(handle), cx, ) - .detach_and_prompt_err("Failed to join channel", cx, |_, _| None) + .detach_and_prompt_err("Failed to join channel", window, cx, |_, _, _| None) } - fn join_channel_chat(&mut self, channel_id: ChannelId, cx: &mut ViewContext) { + fn join_channel_chat( + &mut self, + channel_id: ChannelId, + window: &mut Window, + cx: &mut Context, + ) { let Some(workspace) = self.workspace.upgrade() else { return; }; - cx.window_context().defer(move |cx| { + window.defer(cx, move |window, cx| { workspace.update(cx, |workspace, cx| { - if let Some(panel) = workspace.focus_panel::(cx) { + if let Some(panel) = workspace.focus_panel::(window, cx) { panel.update(cx, |panel, cx| { panel .select_channel(channel_id, None, cx) - .detach_and_notify_err(cx); + .detach_and_notify_err(window, cx); }); } }); }); } - fn copy_channel_link(&mut self, channel_id: ChannelId, cx: &mut ViewContext) { + fn copy_channel_link(&mut self, channel_id: ChannelId, cx: &mut Context) { let channel_store = self.channel_store.read(cx); let Some(channel) = channel_store.channel_for_id(channel_id) else { return; @@ -1974,7 +2144,7 @@ impl CollabPanel { cx.write_to_clipboard(item) } - fn render_signed_out(&mut self, cx: &mut ViewContext) -> Div { + fn render_signed_out(&mut self, cx: &mut Context) -> Div { let collab_blurb = "Work with your team in realtime with collaborative editing, voice, shared notes and more."; v_flex() @@ -1991,9 +2161,9 @@ impl CollabPanel { .icon_position(IconPosition::Start) .style(ButtonStyle::Filled) .full_width() - .on_click(cx.listener(|this, _, cx| { + .on_click(cx.listener(|this, _, window, cx| { let client = this.client.clone(); - cx.spawn(|_, mut cx| async move { + cx.spawn_in(window, |_, mut cx| async move { client .authenticate_and_connect(true, &cx) .await @@ -2012,7 +2182,12 @@ impl CollabPanel { ) } - fn render_list_entry(&mut self, ix: usize, cx: &mut ViewContext) -> AnyElement { + fn render_list_entry( + &mut self, + ix: usize, + window: &mut Window, + cx: &mut Context, + ) -> AnyElement { let entry = &self.entries[ix]; let is_selected = self.selection == Some(ix); @@ -2041,9 +2216,9 @@ impl CollabPanel { } => self .render_channel(channel, *depth, *has_children, is_selected, ix, cx) .into_any_element(), - ListEntry::ChannelEditor { depth } => { - self.render_channel_editor(*depth, cx).into_any_element() - } + ListEntry::ChannelEditor { depth } => self + .render_channel_editor(*depth, window, cx) + .into_any_element(), ListEntry::ChannelInvite(channel) => self .render_channel_invite(channel, is_selected, cx) .into_any_element(), @@ -2067,22 +2242,23 @@ impl CollabPanel { *host_user_id, *is_last, is_selected, + window, cx, ) .into_any_element(), ListEntry::ParticipantScreen { peer_id, is_last } => self - .render_participant_screen(*peer_id, *is_last, is_selected, cx) + .render_participant_screen(*peer_id, *is_last, is_selected, window, cx) .into_any_element(), ListEntry::ChannelNotes { channel_id } => self - .render_channel_notes(*channel_id, is_selected, cx) + .render_channel_notes(*channel_id, is_selected, window, cx) .into_any_element(), ListEntry::ChannelChat { channel_id } => self - .render_channel_chat(*channel_id, is_selected, cx) + .render_channel_chat(*channel_id, is_selected, window, cx) .into_any_element(), } } - fn render_signed_in(&mut self, cx: &mut ViewContext) -> Div { + fn render_signed_in(&mut self, _: &mut Window, cx: &mut Context) -> Div { self.channel_store.update(cx, |channel_store, _| { channel_store.initialize(); }); @@ -2102,8 +2278,8 @@ impl CollabPanel { fn render_filter_input( &self, - editor: &View, - cx: &mut ViewContext, + editor: &Entity, + cx: &mut Context, ) -> impl IntoElement { let settings = ThemeSettings::get_global(cx); let text_style = TextStyle { @@ -2137,7 +2313,7 @@ impl CollabPanel { section: Section, is_selected: bool, is_collapsed: bool, - cx: &ViewContext, + cx: &mut Context, ) -> impl IntoElement { let mut channel_link = None; let mut channel_tooltip_text = None; @@ -2184,23 +2360,25 @@ impl CollabPanel { .icon_size(IconSize::Small) .size(ButtonSize::None) .visible_on_hover("section-header") - .on_click(move |_, cx| { + .on_click(move |_, _, cx| { let item = ClipboardItem::new_string(channel_link_copy.clone()); cx.write_to_clipboard(item) }) - .tooltip(|cx| Tooltip::text("Copy channel link", cx)) + .tooltip(Tooltip::text("Copy channel link")) .into_any_element() }), Section::Contacts => Some( IconButton::new("add-contact", IconName::Plus) - .on_click(cx.listener(|this, _, cx| this.toggle_contact_finder(cx))) - .tooltip(|cx| Tooltip::text("Search for new contact", cx)) + .on_click( + cx.listener(|this, _, window, cx| this.toggle_contact_finder(window, cx)), + ) + .tooltip(Tooltip::text("Search for new contact")) .into_any_element(), ), Section::Channels => Some( IconButton::new("add-channel", IconName::Plus) - .on_click(cx.listener(|this, _, cx| this.new_root_channel(cx))) - .tooltip(|cx| Tooltip::text("Create a channel", cx)) + .on_click(cx.listener(|this, _, window, cx| this.new_root_channel(window, cx))) + .tooltip(Tooltip::text("Create a channel")) .into_any_element(), ), _ => None, @@ -2217,11 +2395,11 @@ impl CollabPanel { h_flex().w_full().group("section-header").child( ListHeader::new(text) .when(can_collapse, |header| { - header - .toggle(Some(!is_collapsed)) - .on_toggle(cx.listener(move |this, _, cx| { + header.toggle(Some(!is_collapsed)).on_toggle(cx.listener( + move |this, _, _, cx| { this.toggle_section_expanded(section, cx); - })) + }, + )) }) .inset(true) .end_slot::(button) @@ -2234,7 +2412,7 @@ impl CollabPanel { contact: &Arc, calling: bool, is_selected: bool, - cx: &mut ViewContext, + cx: &mut Context, ) -> impl IntoElement { let online = contact.online; let busy = contact.busy || calling; @@ -2258,10 +2436,11 @@ impl CollabPanel { .visible_on_hover("") .on_click(cx.listener({ let contact = contact.clone(); - move |this, event: &ClickEvent, cx| { + move |this, event: &ClickEvent, window, cx| { this.deploy_contact_context_menu( event.down.position, contact.clone(), + window, cx, ); } @@ -2271,8 +2450,8 @@ impl CollabPanel { ) .on_secondary_mouse_down(cx.listener({ let contact = contact.clone(); - move |this, event: &MouseDownEvent, cx| { - this.deploy_contact_context_menu(event.position, contact.clone(), cx); + move |this, event: &MouseDownEvent, window, cx| { + this.deploy_contact_context_menu(event.position, contact.clone(), window, cx); } })) .start_slot( @@ -2292,7 +2471,7 @@ impl CollabPanel { .id(github_login.clone()) .group("") .child(item) - .tooltip(move |cx| { + .tooltip(move |_, cx| { let text = if !online { format!(" {} is offline", &github_login) } else if busy { @@ -2305,7 +2484,7 @@ impl CollabPanel { format!("Call {}", &github_login) } }; - Tooltip::text(text, cx) + Tooltip::simple(text, cx) }) } @@ -2314,7 +2493,7 @@ impl CollabPanel { user: &Arc, is_incoming: bool, is_selected: bool, - cx: &mut ViewContext, + cx: &mut Context, ) -> impl IntoElement { let github_login = SharedString::from(user.github_login.clone()); let user_id = user.id; @@ -2328,26 +2507,26 @@ impl CollabPanel { let controls = if is_incoming { vec![ IconButton::new("decline-contact", IconName::Close) - .on_click(cx.listener(move |this, _, cx| { - this.respond_to_contact_request(user_id, false, cx); + .on_click(cx.listener(move |this, _, window, cx| { + this.respond_to_contact_request(user_id, false, window, cx); })) .icon_color(color) - .tooltip(|cx| Tooltip::text("Decline invite", cx)), + .tooltip(Tooltip::text("Decline invite")), IconButton::new("accept-contact", IconName::Check) - .on_click(cx.listener(move |this, _, cx| { - this.respond_to_contact_request(user_id, true, cx); + .on_click(cx.listener(move |this, _, window, cx| { + this.respond_to_contact_request(user_id, true, window, cx); })) .icon_color(color) - .tooltip(|cx| Tooltip::text("Accept invite", cx)), + .tooltip(Tooltip::text("Accept invite")), ] } else { let github_login = github_login.clone(); vec![IconButton::new("remove_contact", IconName::Close) - .on_click(cx.listener(move |this, _, cx| { - this.remove_contact(user_id, &github_login, cx); + .on_click(cx.listener(move |this, _, window, cx| { + this.remove_contact(user_id, &github_login, window, cx); })) .icon_color(color) - .tooltip(|cx| Tooltip::text("Cancel invite", cx))] + .tooltip(Tooltip::text("Cancel invite"))] }; ListItem::new(github_login.clone()) @@ -2368,7 +2547,7 @@ impl CollabPanel { &self, channel: &Arc, is_selected: bool, - cx: &mut ViewContext, + cx: &mut Context, ) -> ListItem { let channel_id = channel.id; let response_is_pending = self @@ -2383,17 +2562,17 @@ impl CollabPanel { let controls = [ IconButton::new("reject-invite", IconName::Close) - .on_click(cx.listener(move |this, _, cx| { + .on_click(cx.listener(move |this, _, _, cx| { this.respond_to_channel_invite(channel_id, false, cx); })) .icon_color(color) - .tooltip(|cx| Tooltip::text("Decline invite", cx)), + .tooltip(Tooltip::text("Decline invite")), IconButton::new("accept-invite", IconName::Check) - .on_click(cx.listener(move |this, _, cx| { + .on_click(cx.listener(move |this, _, _, cx| { this.respond_to_channel_invite(channel_id, true, cx); })) .icon_color(color) - .tooltip(|cx| Tooltip::text("Accept invite", cx)), + .tooltip(Tooltip::text("Accept invite")), ]; ListItem::new(("channel-invite", channel.id.0 as usize)) @@ -2412,16 +2591,12 @@ impl CollabPanel { ) } - fn render_contact_placeholder( - &self, - is_selected: bool, - cx: &mut ViewContext, - ) -> ListItem { + fn render_contact_placeholder(&self, is_selected: bool, cx: &mut Context) -> ListItem { ListItem::new("contact-placeholder") .child(Icon::new(IconName::Plus)) .child(Label::new("Add a Contact")) .toggle_state(is_selected) - .on_click(cx.listener(|this, _, cx| this.toggle_contact_finder(cx))) + .on_click(cx.listener(|this, _, window, cx| this.toggle_contact_finder(window, cx))) } fn render_channel( @@ -2431,7 +2606,7 @@ impl CollabPanel { has_children: bool, is_selected: bool, ix: usize, - cx: &mut ViewContext, + cx: &mut Context, ) -> impl IntoElement { let channel_id = channel.id; @@ -2492,15 +2667,15 @@ impl CollabPanel { .flex() .w_full() .when(!channel.is_root_channel(), |el| { - el.on_drag(channel.clone(), move |channel, _, cx| { - cx.new_view(|_| DraggedChannelView { + el.on_drag(channel.clone(), move |channel, _, _, cx| { + cx.new(|_| DraggedChannelView { channel: channel.clone(), width, }) }) }) .drag_over::({ - move |style, dragged_channel: &Channel, cx| { + move |style, dragged_channel: &Channel, _window, cx| { if dragged_channel.root_id() == root_id { style.bg(cx.theme().colors().ghost_element_hover) } else { @@ -2508,12 +2683,14 @@ impl CollabPanel { } } }) - .on_drop(cx.listener(move |this, dragged_channel: &Channel, cx| { - if dragged_channel.root_id() != root_id { - return; - } - this.move_channel(dragged_channel.id, channel_id, cx); - })) + .on_drop( + cx.listener(move |this, dragged_channel: &Channel, window, cx| { + if dragged_channel.root_id() != root_id { + return; + } + this.move_channel(dragged_channel.id, channel_id, window, cx); + }), + ) .child( ListItem::new(channel_id.0 as usize) // Add one level of depth for the disclosure arrow. @@ -2521,21 +2698,25 @@ impl CollabPanel { .indent_step_size(px(20.)) .toggle_state(is_selected || is_active) .toggle(disclosed) - .on_toggle( - cx.listener(move |this, _, cx| { - this.toggle_channel_collapsed(channel_id, cx) - }), - ) - .on_click(cx.listener(move |this, _, cx| { + .on_toggle(cx.listener(move |this, _, window, cx| { + this.toggle_channel_collapsed(channel_id, window, cx) + })) + .on_click(cx.listener(move |this, _, window, cx| { if is_active { - this.open_channel_notes(channel_id, cx) + this.open_channel_notes(channel_id, window, cx) } else { - this.join_channel(channel_id, cx) + this.join_channel(channel_id, window, cx) } })) .on_secondary_mouse_down(cx.listener( - move |this, event: &MouseDownEvent, cx| { - this.deploy_channel_context_menu(event.position, channel_id, ix, cx) + move |this, event: &MouseDownEvent, window, cx| { + this.deploy_channel_context_menu( + event.position, + channel_id, + ix, + window, + cx, + ) }, )) .start_slot( @@ -2582,10 +2763,10 @@ impl CollabPanel { } else { Color::Muted }) - .on_click(cx.listener(move |this, _, cx| { - this.join_channel_chat(channel_id, cx) + .on_click(cx.listener(move |this, _, window, cx| { + this.join_channel_chat(channel_id, window, cx) })) - .tooltip(|cx| Tooltip::text("Open channel chat", cx)) + .tooltip(Tooltip::text("Open channel chat")) .visible_on_hover(""), ) .child( @@ -2598,18 +2779,18 @@ impl CollabPanel { } else { Color::Muted }) - .on_click(cx.listener(move |this, _, cx| { - this.open_channel_notes(channel_id, cx) + .on_click(cx.listener(move |this, _, window, cx| { + this.open_channel_notes(channel_id, window, cx) })) - .tooltip(|cx| Tooltip::text("Open channel notes", cx)) + .tooltip(Tooltip::text("Open channel notes")) .visible_on_hover(""), ), ), ) .tooltip({ let channel_store = self.channel_store.clone(); - move |cx| { - cx.new_view(|_| JoinChannelTooltip { + move |_window, cx| { + cx.new(|_| JoinChannelTooltip { channel_store: channel_store.clone(), channel_id, has_notes_notification, @@ -2619,7 +2800,12 @@ impl CollabPanel { }) } - fn render_channel_editor(&self, depth: usize, _cx: &mut ViewContext) -> impl IntoElement { + fn render_channel_editor( + &self, + depth: usize, + _window: &mut Window, + _cx: &mut Context, + ) -> impl IntoElement { let item = ListItem::new("channel-editor") .inset(false) // Add one level of depth for the disclosure arrow. @@ -2643,22 +2829,27 @@ impl CollabPanel { } } -fn render_tree_branch(is_last: bool, overdraw: bool, cx: &mut WindowContext) -> impl IntoElement { - let rem_size = cx.rem_size(); - let line_height = cx.text_style().line_height_in_pixels(rem_size); +fn render_tree_branch( + is_last: bool, + overdraw: bool, + window: &mut Window, + cx: &mut App, +) -> impl IntoElement { + let rem_size = window.rem_size(); + let line_height = window.text_style().line_height_in_pixels(rem_size); let width = rem_size * 1.5; let thickness = px(1.); let color = cx.theme().colors().text; canvas( - |_, _| {}, - move |bounds, _, cx| { + |_, _, _| {}, + move |bounds, _, window, _| { let start_x = (bounds.left() + bounds.right() - thickness) / 2.; let start_y = (bounds.top() + bounds.bottom() - thickness) / 2.; let right = bounds.right(); let top = bounds.top(); - cx.paint_quad(fill( + window.paint_quad(fill( Bounds::from_corners( point(start_x, top), point( @@ -2672,7 +2863,7 @@ fn render_tree_branch(is_last: bool, overdraw: bool, cx: &mut WindowContext) -> ), color, )); - cx.paint_quad(fill( + window.paint_quad(fill( Bounds::from_corners(point(start_x, start_y), point(right, start_y + thickness)), color, )); @@ -2683,7 +2874,7 @@ fn render_tree_branch(is_last: bool, overdraw: bool, cx: &mut WindowContext) -> } impl Render for CollabPanel { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { v_flex() .key_context("CollabPanel") .on_action(cx.listener(CollabPanel::cancel)) @@ -2702,7 +2893,7 @@ impl Render for CollabPanel { .child(if self.user_store.read(cx).current_user().is_none() { self.render_signed_out(cx) } else { - self.render_signed_in(cx) + self.render_signed_in(window, cx) }) .children(self.context_menu.as_ref().map(|(menu, position, _)| { deferred( @@ -2719,7 +2910,7 @@ impl Render for CollabPanel { impl EventEmitter for CollabPanel {} impl Panel for CollabPanel { - fn position(&self, cx: &WindowContext) -> DockPosition { + fn position(&self, _window: &Window, cx: &App) -> DockPosition { CollaborationPanelSettings::get_global(cx).dock } @@ -2727,7 +2918,12 @@ impl Panel for CollabPanel { matches!(position, DockPosition::Left | DockPosition::Right) } - fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext) { + fn set_position( + &mut self, + position: DockPosition, + _window: &mut Window, + cx: &mut Context, + ) { settings::update_settings_file::( self.fs.clone(), cx, @@ -2735,24 +2931,24 @@ impl Panel for CollabPanel { ); } - fn size(&self, cx: &WindowContext) -> Pixels { + fn size(&self, _window: &Window, cx: &App) -> Pixels { self.width .unwrap_or_else(|| CollaborationPanelSettings::get_global(cx).default_width) } - fn set_size(&mut self, size: Option, cx: &mut ViewContext) { + fn set_size(&mut self, size: Option, _: &mut Window, cx: &mut Context) { self.width = size; self.serialize(cx); cx.notify(); } - fn icon(&self, cx: &WindowContext) -> Option { + fn icon(&self, _window: &Window, cx: &App) -> Option { CollaborationPanelSettings::get_global(cx) .button .then_some(ui::IconName::UserGroup) } - fn icon_tooltip(&self, _cx: &WindowContext) -> Option<&'static str> { + fn icon_tooltip(&self, _window: &Window, _cx: &App) -> Option<&'static str> { Some("Collab Panel") } @@ -2769,8 +2965,8 @@ impl Panel for CollabPanel { } } -impl FocusableView for CollabPanel { - fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle { +impl Focusable for CollabPanel { + fn focus_handle(&self, cx: &App) -> gpui::FocusHandle { self.filter_editor.focus_handle(cx).clone() } } @@ -2882,7 +3078,7 @@ struct DraggedChannelView { } impl Render for DraggedChannelView { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { let ui_font = ThemeSettings::get_global(cx).ui_font.family.clone(); h_flex() .font_family(ui_font) @@ -2906,15 +3102,15 @@ impl Render for DraggedChannelView { } struct JoinChannelTooltip { - channel_store: Model, + channel_store: Entity, channel_id: ChannelId, #[allow(unused)] has_notes_notification: bool, } impl Render for JoinChannelTooltip { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { - tooltip_container(cx, |container, cx| { + fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { + tooltip_container(window, cx, |container, _, cx| { let participants = self .channel_store .read(cx) diff --git a/crates/collab_ui/src/collab_panel/channel_modal.rs b/crates/collab_ui/src/collab_panel/channel_modal.rs index a4a7acd1e5..0568aa7faf 100644 --- a/crates/collab_ui/src/collab_panel/channel_modal.rs +++ b/crates/collab_ui/src/collab_panel/channel_modal.rs @@ -5,9 +5,8 @@ use client::{ }; use fuzzy::{match_strings, StringMatchCandidate}; use gpui::{ - actions, anchored, deferred, div, AppContext, ClipboardItem, DismissEvent, EventEmitter, - FocusableView, Model, ParentElement, Render, Styled, Subscription, Task, View, ViewContext, - VisualContext, WeakView, + actions, anchored, deferred, div, App, ClipboardItem, Context, DismissEvent, Entity, + EventEmitter, Focusable, ParentElement, Render, Styled, Subscription, Task, WeakEntity, Window, }; use picker::{Picker, PickerDelegate}; use std::sync::Arc; @@ -26,22 +25,23 @@ actions!( ); pub struct ChannelModal { - picker: View>, - channel_store: Model, + picker: Entity>, + channel_store: Entity, channel_id: ChannelId, } impl ChannelModal { pub fn new( - user_store: Model, - channel_store: Model, + user_store: Entity, + channel_store: Entity, channel_id: ChannelId, mode: Mode, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Self { cx.observe(&channel_store, |_, _, cx| cx.notify()).detach(); - let channel_modal = cx.view().downgrade(); - let picker = cx.new_view(|cx| { + let channel_modal = cx.model().downgrade(); + let picker = cx.new(|cx| { Picker::uniform_list( ChannelModalDelegate { channel_modal, @@ -57,6 +57,7 @@ impl ChannelModal { has_all_members: false, mode, }, + window, cx, ) .modal(false) @@ -69,27 +70,32 @@ impl ChannelModal { } } - fn toggle_mode(&mut self, _: &ToggleMode, cx: &mut ViewContext) { + fn toggle_mode(&mut self, _: &ToggleMode, window: &mut Window, cx: &mut Context) { let mode = match self.picker.read(cx).delegate.mode { Mode::ManageMembers => Mode::InviteMembers, Mode::InviteMembers => Mode::ManageMembers, }; - self.set_mode(mode, cx); + self.set_mode(mode, window, cx); } - fn set_mode(&mut self, mode: Mode, cx: &mut ViewContext) { + fn set_mode(&mut self, mode: Mode, window: &mut Window, cx: &mut Context) { self.picker.update(cx, |picker, cx| { let delegate = &mut picker.delegate; delegate.mode = mode; delegate.selected_index = 0; - picker.set_query("", cx); - picker.update_matches(picker.query(cx), cx); + picker.set_query("", window, cx); + picker.update_matches(picker.query(cx), window, cx); cx.notify() }); cx.notify() } - fn set_channel_visibility(&mut self, selection: &ToggleState, cx: &mut ViewContext) { + fn set_channel_visibility( + &mut self, + selection: &ToggleState, + _: &mut Window, + cx: &mut Context, + ) { self.channel_store.update(cx, |channel_store, cx| { channel_store .set_channel_visibility( @@ -105,7 +111,7 @@ impl ChannelModal { }); } - fn dismiss(&mut self, _: &menu::Cancel, cx: &mut ViewContext) { + fn dismiss(&mut self, _: &menu::Cancel, _: &mut Window, cx: &mut Context) { cx.emit(DismissEvent); } } @@ -113,14 +119,14 @@ impl ChannelModal { impl EventEmitter for ChannelModal {} impl ModalView for ChannelModal {} -impl FocusableView for ChannelModal { - fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle { +impl Focusable for ChannelModal { + fn focus_handle(&self, cx: &App) -> gpui::FocusHandle { self.picker.focus_handle(cx) } } impl Render for ChannelModal { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { let channel_store = self.channel_store.read(cx); let Some(channel) = channel_store.channel_for_id(self.channel_id) else { return div(); @@ -169,7 +175,7 @@ impl Render for ChannelModal { Some( Button::new("copy-link", "Copy Link") .label_size(LabelSize::Small) - .on_click(cx.listener(move |this, _, cx| { + .on_click(cx.listener(move |this, _, _, cx| { if let Some(channel) = this .channel_store .read(cx) @@ -197,8 +203,8 @@ impl Render for ChannelModal { this.border_color(cx.theme().colors().border) }) .child(Label::new("Manage Members")) - .on_click(cx.listener(|this, _, cx| { - this.set_mode(Mode::ManageMembers, cx); + .on_click(cx.listener(|this, _, window, cx| { + this.set_mode(Mode::ManageMembers, window, cx); })), ) .child( @@ -212,8 +218,8 @@ impl Render for ChannelModal { this.border_color(cx.theme().colors().border) }) .child(Label::new("Invite Members")) - .on_click(cx.listener(|this, _, cx| { - this.set_mode(Mode::InviteMembers, cx); + .on_click(cx.listener(|this, _, window, cx| { + this.set_mode(Mode::InviteMembers, window, cx); })), ), ), @@ -229,24 +235,24 @@ pub enum Mode { } pub struct ChannelModalDelegate { - channel_modal: WeakView, + channel_modal: WeakEntity, matching_users: Vec>, matching_member_indices: Vec, - user_store: Model, - channel_store: Model, + user_store: Entity, + channel_store: Entity, channel_id: ChannelId, selected_index: usize, mode: Mode, match_candidates: Vec, members: Vec, has_all_members: bool, - context_menu: Option<(View, Subscription)>, + context_menu: Option<(Entity, Subscription)>, } impl PickerDelegate for ChannelModalDelegate { type ListItem = ListItem; - fn placeholder_text(&self, _cx: &mut WindowContext) -> Arc { + fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc { "Search collaborator by username...".into() } @@ -261,11 +267,21 @@ impl PickerDelegate for ChannelModalDelegate { self.selected_index } - fn set_selected_index(&mut self, ix: usize, _: &mut ViewContext>) { + fn set_selected_index( + &mut self, + ix: usize, + _window: &mut Window, + _: &mut Context>, + ) { self.selected_index = ix; } - fn update_matches(&mut self, query: String, cx: &mut ViewContext>) -> Task<()> { + fn update_matches( + &mut self, + query: String, + window: &mut Window, + cx: &mut Context>, + ) -> Task<()> { match self.mode { Mode::ManageMembers => { if self.has_all_members { @@ -284,7 +300,7 @@ impl PickerDelegate for ChannelModalDelegate { cx.background_executor().clone(), )); - cx.spawn(|picker, mut cx| async move { + cx.spawn_in(window, |picker, mut cx| async move { picker .update(&mut cx, |picker, cx| { let delegate = &mut picker.delegate; @@ -300,7 +316,7 @@ impl PickerDelegate for ChannelModalDelegate { let search_members = self.channel_store.update(cx, |store, cx| { store.fuzzy_search_members(self.channel_id, query.clone(), 100, cx) }); - cx.spawn(|picker, mut cx| async move { + cx.spawn_in(window, |picker, mut cx| async move { async { let members = search_members.await?; picker.update(&mut cx, |picker, cx| { @@ -322,7 +338,7 @@ impl PickerDelegate for ChannelModalDelegate { let search_users = self .user_store .update(cx, |store, cx| store.fuzzy_search_users(query, cx)); - cx.spawn(|picker, mut cx| async move { + cx.spawn_in(window, |picker, mut cx| async move { async { let users = search_users.await?; picker.update(&mut cx, |picker, cx| { @@ -338,26 +354,26 @@ impl PickerDelegate for ChannelModalDelegate { } } - fn confirm(&mut self, _: bool, cx: &mut ViewContext>) { + fn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context>) { if let Some(selected_user) = self.user_at_index(self.selected_index) { if Some(selected_user.id) == self.user_store.read(cx).current_user().map(|user| user.id) { return; } match self.mode { - Mode::ManageMembers => self.show_context_menu(self.selected_index, cx), + Mode::ManageMembers => self.show_context_menu(self.selected_index, window, cx), Mode::InviteMembers => match self.member_status(selected_user.id, cx) { Some(proto::channel_member::Kind::Invitee) => { - self.remove_member(selected_user.id, cx); + self.remove_member(selected_user.id, window, cx); } Some(proto::channel_member::Kind::Member) => {} - None => self.invite_member(selected_user, cx), + None => self.invite_member(selected_user, window, cx), }, } } } - fn dismissed(&mut self, cx: &mut ViewContext>) { + fn dismissed(&mut self, _: &mut Window, cx: &mut Context>) { if self.context_menu.is_none() { self.channel_modal .update(cx, |_, cx| { @@ -371,7 +387,8 @@ impl PickerDelegate for ChannelModalDelegate { &self, ix: usize, selected: bool, - cx: &mut ViewContext>, + _: &mut Window, + cx: &mut Context>, ) -> Option { let user = self.user_at_index(ix)?; let membership = self.member_at_index(ix); @@ -434,11 +451,7 @@ impl PickerDelegate for ChannelModalDelegate { } impl ChannelModalDelegate { - fn member_status( - &self, - user_id: UserId, - cx: &AppContext, - ) -> Option { + fn member_status(&self, user_id: UserId, cx: &App) -> Option { self.members .iter() .find_map(|membership| (membership.user.id == user_id).then_some(membership.kind)) @@ -470,33 +483,39 @@ impl ChannelModalDelegate { &mut self, user_id: UserId, new_role: ChannelRole, - cx: &mut ViewContext>, + window: &mut Window, + cx: &mut Context>, ) -> Option<()> { let update = self.channel_store.update(cx, |store, cx| { store.set_member_role(self.channel_id, user_id, new_role, cx) }); - cx.spawn(|picker, mut cx| async move { + cx.spawn_in(window, |picker, mut cx| async move { update.await?; - picker.update(&mut cx, |picker, cx| { + picker.update_in(&mut cx, |picker, window, cx| { let this = &mut picker.delegate; if let Some(member) = this.members.iter_mut().find(|m| m.user.id == user_id) { member.role = new_role; } - cx.focus_self(); + cx.focus_self(window); cx.notify(); }) }) - .detach_and_prompt_err("Failed to update role", cx, |_, _| None); + .detach_and_prompt_err("Failed to update role", window, cx, |_, _, _| None); Some(()) } - fn remove_member(&mut self, user_id: UserId, cx: &mut ViewContext>) -> Option<()> { + fn remove_member( + &mut self, + user_id: UserId, + window: &mut Window, + cx: &mut Context>, + ) -> Option<()> { let update = self.channel_store.update(cx, |store, cx| { store.remove_member(self.channel_id, user_id, cx) }); - cx.spawn(|picker, mut cx| async move { + cx.spawn_in(window, |picker, mut cx| async move { update.await?; - picker.update(&mut cx, |picker, cx| { + picker.update_in(&mut cx, |picker, window, cx| { let this = &mut picker.delegate; if let Some(ix) = this.members.iter_mut().position(|m| m.user.id == user_id) { this.members.remove(ix); @@ -514,20 +533,25 @@ impl ChannelModalDelegate { .selected_index .min(this.matching_member_indices.len().saturating_sub(1)); - picker.focus(cx); + picker.focus(window, cx); cx.notify(); }) }) - .detach_and_prompt_err("Failed to remove member", cx, |_, _| None); + .detach_and_prompt_err("Failed to remove member", window, cx, |_, _, _| None); Some(()) } - fn invite_member(&mut self, user: Arc, cx: &mut ViewContext>) { + fn invite_member( + &mut self, + user: Arc, + window: &mut Window, + cx: &mut Context>, + ) { let invite_member = self.channel_store.update(cx, |store, cx| { store.invite_member(self.channel_id, user.id, ChannelRole::Member, cx) }); - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { invite_member.await?; this.update(&mut cx, |this, cx| { @@ -544,25 +568,30 @@ impl ChannelModalDelegate { cx.notify(); }) }) - .detach_and_prompt_err("Failed to invite member", cx, |_, _| None); + .detach_and_prompt_err("Failed to invite member", window, cx, |_, _, _| None); } - fn show_context_menu(&mut self, ix: usize, cx: &mut ViewContext>) { + fn show_context_menu( + &mut self, + ix: usize, + window: &mut Window, + cx: &mut Context>, + ) { let Some(membership) = self.member_at_index(ix) else { return; }; let user_id = membership.user.id; - let picker = cx.view().clone(); - let context_menu = ContextMenu::build(cx, |mut menu, _cx| { + let picker = cx.model().clone(); + let context_menu = ContextMenu::build(window, cx, |mut menu, _window, _cx| { let role = membership.role; if role == ChannelRole::Admin || role == ChannelRole::Member { let picker = picker.clone(); - menu = menu.entry("Demote to Guest", None, move |cx| { + menu = menu.entry("Demote to Guest", None, move |window, cx| { picker.update(cx, |picker, cx| { picker .delegate - .set_user_role(user_id, ChannelRole::Guest, cx); + .set_user_role(user_id, ChannelRole::Guest, window, cx); }) }); } @@ -575,22 +604,22 @@ impl ChannelModalDelegate { "Demote to Member" }; - menu = menu.entry(label, None, move |cx| { + menu = menu.entry(label, None, move |window, cx| { picker.update(cx, |picker, cx| { picker .delegate - .set_user_role(user_id, ChannelRole::Member, cx); + .set_user_role(user_id, ChannelRole::Member, window, cx); }) }); } if role == ChannelRole::Member || role == ChannelRole::Guest { let picker = picker.clone(); - menu = menu.entry("Promote to Admin", None, move |cx| { + menu = menu.entry("Promote to Admin", None, move |window, cx| { picker.update(cx, |picker, cx| { picker .delegate - .set_user_role(user_id, ChannelRole::Admin, cx); + .set_user_role(user_id, ChannelRole::Admin, window, cx); }) }); }; @@ -598,20 +627,24 @@ impl ChannelModalDelegate { menu = menu.separator(); menu = menu.entry("Remove from Channel", None, { let picker = picker.clone(); - move |cx| { + move |window, cx| { picker.update(cx, |picker, cx| { - picker.delegate.remove_member(user_id, cx); + picker.delegate.remove_member(user_id, window, cx); }) } }); menu }); - cx.focus_view(&context_menu); - let subscription = cx.subscribe(&context_menu, |picker, _, _: &DismissEvent, cx| { - picker.delegate.context_menu = None; - picker.focus(cx); - cx.notify(); - }); + window.focus(&context_menu.focus_handle(cx)); + let subscription = cx.subscribe_in( + &context_menu, + window, + |picker, _, _: &DismissEvent, window, cx| { + picker.delegate.context_menu = None; + picker.focus(window, cx); + cx.notify(); + }, + ); self.context_menu = Some((context_menu, subscription)); } } diff --git a/crates/collab_ui/src/collab_panel/contact_finder.rs b/crates/collab_ui/src/collab_panel/contact_finder.rs index 96fe44092d..ac499c589e 100644 --- a/crates/collab_ui/src/collab_panel/contact_finder.rs +++ b/crates/collab_ui/src/collab_panel/contact_finder.rs @@ -1,7 +1,7 @@ use client::{ContactRequestStatus, User, UserStore}; use gpui::{ - AppContext, DismissEvent, EventEmitter, FocusHandle, FocusableView, Model, ParentElement as _, - Render, Styled, Task, View, ViewContext, VisualContext, WeakView, + App, Context, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, ParentElement as _, + Render, Styled, Task, WeakEntity, Window, }; use picker::{Picker, PickerDelegate}; use std::sync::Arc; @@ -10,31 +10,31 @@ use util::{ResultExt as _, TryFutureExt}; use workspace::ModalView; pub struct ContactFinder { - picker: View>, + picker: Entity>, } impl ContactFinder { - pub fn new(user_store: Model, cx: &mut ViewContext) -> Self { + pub fn new(user_store: Entity, window: &mut Window, cx: &mut Context) -> Self { let delegate = ContactFinderDelegate { - parent: cx.view().downgrade(), + parent: cx.model().downgrade(), user_store, potential_contacts: Arc::from([]), selected_index: 0, }; - let picker = cx.new_view(|cx| Picker::uniform_list(delegate, cx).modal(false)); + let picker = cx.new(|cx| Picker::uniform_list(delegate, window, cx).modal(false)); Self { picker } } - pub fn set_query(&mut self, query: String, cx: &mut ViewContext) { + pub fn set_query(&mut self, query: String, window: &mut Window, cx: &mut Context) { self.picker.update(cx, |picker, cx| { - picker.set_query(query, cx); + picker.set_query(query, window, cx); }); } } impl Render for ContactFinder { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { v_flex() .elevation_3(cx) .child( @@ -53,17 +53,17 @@ impl Render for ContactFinder { } pub struct ContactFinderDelegate { - parent: WeakView, + parent: WeakEntity, potential_contacts: Arc<[Arc]>, - user_store: Model, + user_store: Entity, selected_index: usize, } impl EventEmitter for ContactFinder {} impl ModalView for ContactFinder {} -impl FocusableView for ContactFinder { - fn focus_handle(&self, cx: &AppContext) -> FocusHandle { +impl Focusable for ContactFinder { + fn focus_handle(&self, cx: &App) -> FocusHandle { self.picker.focus_handle(cx) } } @@ -79,20 +79,30 @@ impl PickerDelegate for ContactFinderDelegate { self.selected_index } - fn set_selected_index(&mut self, ix: usize, _: &mut ViewContext>) { + fn set_selected_index( + &mut self, + ix: usize, + _window: &mut Window, + _: &mut Context>, + ) { self.selected_index = ix; } - fn placeholder_text(&self, _cx: &mut WindowContext) -> Arc { + fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc { "Search collaborator by username...".into() } - fn update_matches(&mut self, query: String, cx: &mut ViewContext>) -> Task<()> { + fn update_matches( + &mut self, + query: String, + window: &mut Window, + cx: &mut Context>, + ) -> Task<()> { let search_users = self .user_store .update(cx, |store, cx| store.fuzzy_search_users(query, cx)); - cx.spawn(|picker, mut cx| async move { + cx.spawn_in(window, |picker, mut cx| async move { async { let potential_contacts = search_users.await?; picker.update(&mut cx, |picker, cx| { @@ -106,7 +116,7 @@ impl PickerDelegate for ContactFinderDelegate { }) } - fn confirm(&mut self, _: bool, cx: &mut ViewContext>) { + fn confirm(&mut self, _: bool, _: &mut Window, cx: &mut Context>) { if let Some(user) = self.potential_contacts.get(self.selected_index) { let user_store = self.user_store.read(cx); match user_store.contact_request_status(user) { @@ -125,7 +135,7 @@ impl PickerDelegate for ContactFinderDelegate { } } - fn dismissed(&mut self, cx: &mut ViewContext>) { + fn dismissed(&mut self, _: &mut Window, cx: &mut Context>) { self.parent .update(cx, |_, cx| cx.emit(DismissEvent)) .log_err(); @@ -135,7 +145,8 @@ impl PickerDelegate for ContactFinderDelegate { &self, ix: usize, selected: bool, - cx: &mut ViewContext>, + _: &mut Window, + cx: &mut Context>, ) -> Option { let user = &self.potential_contacts[ix]; let request_status = self.user_store.read(cx).contact_request_status(user); diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index 148e4806cd..dbc408741c 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -9,7 +9,7 @@ use std::{rc::Rc, sync::Arc}; pub use collab_panel::CollabPanel; use gpui::{ - point, AppContext, Pixels, PlatformDisplay, Size, WindowBackgroundAppearance, WindowBounds, + point, App, Pixels, PlatformDisplay, Size, WindowBackgroundAppearance, WindowBounds, WindowDecorations, WindowKind, WindowOptions, }; use panel_settings::MessageEditorSettings; @@ -21,7 +21,7 @@ use settings::Settings; use ui::px; use workspace::AppState; -pub fn init(app_state: &Arc, cx: &mut AppContext) { +pub fn init(app_state: &Arc, cx: &mut App) { CollaborationPanelSettings::register(cx); ChatPanelSettings::register(cx); NotificationPanelSettings::register(cx); @@ -38,7 +38,7 @@ pub fn init(app_state: &Arc, cx: &mut AppContext) { fn notification_window_options( screen: Rc, size: Size, - cx: &AppContext, + cx: &App, ) -> WindowOptions { let notification_margin_width = px(16.); let notification_margin_height = px(-48.); diff --git a/crates/collab_ui/src/notification_panel.rs b/crates/collab_ui/src/notification_panel.rs index 574316fa4a..4ffb369c53 100644 --- a/crates/collab_ui/src/notification_panel.rs +++ b/crates/collab_ui/src/notification_panel.rs @@ -6,11 +6,10 @@ use collections::HashMap; use db::kvp::KEY_VALUE_STORE; use futures::StreamExt; use gpui::{ - actions, div, img, list, px, AnyElement, AppContext, AsyncWindowContext, CursorStyle, - DismissEvent, Element, EventEmitter, FocusHandle, FocusableView, InteractiveElement, - IntoElement, ListAlignment, ListScrollEvent, ListState, Model, ParentElement, Render, - StatefulInteractiveElement, Styled, Task, View, ViewContext, VisualContext, WeakView, - WindowContext, + actions, div, img, list, px, AnyElement, App, AsyncWindowContext, Context, CursorStyle, + DismissEvent, Element, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement, + IntoElement, ListAlignment, ListScrollEvent, ListState, ParentElement, Render, + StatefulInteractiveElement, Styled, Task, WeakEntity, Window, }; use notifications::{NotificationEntry, NotificationEvent, NotificationStore}; use project::Fs; @@ -36,16 +35,16 @@ const NOTIFICATION_PANEL_KEY: &str = "NotificationPanel"; pub struct NotificationPanel { client: Arc, - user_store: Model, - channel_store: Model, - notification_store: Model, + user_store: Entity, + channel_store: Entity, + notification_store: Entity, fs: Arc, width: Option, active: bool, notification_list: ListState, pending_serialization: Task>, subscriptions: Vec, - workspace: WeakView, + workspace: WeakEntity, current_notification_toast: Option<(u64, Task<()>)>, local_timezone: UtcOffset, focus_handle: FocusHandle, @@ -75,28 +74,32 @@ pub struct NotificationPresenter { actions!(notification_panel, [ToggleFocus]); -pub fn init(cx: &mut AppContext) { - cx.observe_new_views(|workspace: &mut Workspace, _| { - workspace.register_action(|workspace, _: &ToggleFocus, cx| { - workspace.toggle_panel_focus::(cx); +pub fn init(cx: &mut App) { + cx.observe_new(|workspace: &mut Workspace, _, _| { + workspace.register_action(|workspace, _: &ToggleFocus, window, cx| { + workspace.toggle_panel_focus::(window, cx); }); }) .detach(); } impl NotificationPanel { - pub fn new(workspace: &mut Workspace, cx: &mut ViewContext) -> View { + pub fn new( + workspace: &mut Workspace, + window: &mut Window, + cx: &mut Context, + ) -> Entity { let fs = workspace.app_state().fs.clone(); let client = workspace.app_state().client.clone(); let user_store = workspace.app_state().user_store.clone(); let workspace_handle = workspace.weak_handle(); - cx.new_view(|cx: &mut ViewContext| { + cx.new(|cx| { let mut status = client.status(); - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { while (status.next().await).is_some() { if this - .update(&mut cx, |_, cx| { + .update(&mut cx, |_: &mut Self, cx| { cx.notify(); }) .is_err() @@ -107,17 +110,18 @@ impl NotificationPanel { }) .detach(); - let view = cx.view().downgrade(); + let model = cx.model().downgrade(); let notification_list = - ListState::new(0, ListAlignment::Top, px(1000.), move |ix, cx| { - view.upgrade() - .and_then(|view| { - view.update(cx, |this, cx| this.render_notification(ix, cx)) + ListState::new(0, ListAlignment::Top, px(1000.), move |ix, window, cx| { + model + .upgrade() + .and_then(|model| { + model.update(cx, |this, cx| this.render_notification(ix, window, cx)) }) .unwrap_or_else(|| div().into_any()) }); notification_list.set_scroll_handler(cx.listener( - |this, event: &ListScrollEvent, cx| { + |this, event: &ListScrollEvent, _, cx| { if event.count.saturating_sub(event.visible_range.end) < LOADING_THRESHOLD { if let Some(task) = this .notification_store @@ -149,27 +153,34 @@ impl NotificationPanel { unseen_notifications: Vec::new(), }; - let mut old_dock_position = this.position(cx); + let mut old_dock_position = this.position(window, cx); this.subscriptions.extend([ cx.observe(&this.notification_store, |_, _, cx| cx.notify()), - cx.subscribe(&this.notification_store, Self::on_notification_event), - cx.observe_global::(move |this: &mut Self, cx| { - let new_dock_position = this.position(cx); - if new_dock_position != old_dock_position { - old_dock_position = new_dock_position; - cx.emit(Event::DockPositionChanged); - } - cx.notify(); - }), + cx.subscribe_in( + &this.notification_store, + window, + Self::on_notification_event, + ), + cx.observe_global_in::( + window, + move |this: &mut Self, window, cx| { + let new_dock_position = this.position(window, cx); + if new_dock_position != old_dock_position { + old_dock_position = new_dock_position; + cx.emit(Event::DockPositionChanged); + } + cx.notify(); + }, + ), ]); this }) } pub fn load( - workspace: WeakView, + workspace: WeakEntity, cx: AsyncWindowContext, - ) -> Task>> { + ) -> Task>> { cx.spawn(|mut cx| async move { let serialized_panel = if let Some(panel) = cx .background_executor() @@ -183,8 +194,8 @@ impl NotificationPanel { None }; - workspace.update(&mut cx, |workspace, cx| { - let panel = Self::new(workspace, cx); + workspace.update_in(&mut cx, |workspace, window, cx| { + let panel = Self::new(workspace, window, cx); if let Some(serialized_panel) = serialized_panel { panel.update(cx, |panel, cx| { panel.width = serialized_panel.width.map(|w| w.round()); @@ -196,7 +207,7 @@ impl NotificationPanel { }) } - fn serialize(&mut self, cx: &mut ViewContext) { + fn serialize(&mut self, cx: &mut Context) { let width = self.width; self.pending_serialization = cx.background_executor().spawn( async move { @@ -212,7 +223,12 @@ impl NotificationPanel { ); } - fn render_notification(&mut self, ix: usize, cx: &mut ViewContext) -> Option { + fn render_notification( + &mut self, + ix: usize, + window: &mut Window, + cx: &mut Context, + ) -> Option { let entry = self.notification_store.read(cx).notification_at(ix)?; let notification_id = entry.id; let now = OffsetDateTime::now_utc(); @@ -229,7 +245,7 @@ impl NotificationPanel { let notification = entry.notification.clone(); if self.active && !entry.is_read { - self.did_render_notification(notification_id, ¬ification, cx); + self.did_render_notification(notification_id, ¬ification, window, cx); } let relative_timestamp = time_format::format_localized_timestamp( @@ -259,8 +275,8 @@ impl NotificationPanel { .when(can_navigate, |el| { el.cursor(CursorStyle::PointingHand).on_click({ let notification = notification.clone(); - cx.listener(move |this, _, cx| { - this.did_click_notification(¬ification, cx) + cx.listener(move |this, _, window, cx| { + this.did_click_notification(¬ification, window, cx) }) }) }) @@ -288,8 +304,8 @@ impl NotificationPanel { .rounded_md() }) .child(Label::new(relative_timestamp).color(Color::Muted)) - .tooltip(move |cx| { - Tooltip::text(absolute_timestamp.clone(), cx) + .tooltip(move |_, cx| { + Tooltip::simple(absolute_timestamp.clone(), cx) }), ) .children(if let Some(is_accepted) = response { @@ -307,9 +323,9 @@ impl NotificationPanel { .justify_end() .child(Button::new("decline", "Decline").on_click({ let notification = notification.clone(); - let view = cx.view().clone(); - move |_, cx| { - view.update(cx, |this, cx| { + let model = cx.model().clone(); + move |_, _, cx| { + model.update(cx, |this, cx| { this.respond_to_notification( notification.clone(), false, @@ -320,9 +336,9 @@ impl NotificationPanel { })) .child(Button::new("accept", "Accept").on_click({ let notification = notification.clone(); - let view = cx.view().clone(); - move |_, cx| { - view.update(cx, |this, cx| { + let model = cx.model().clone(); + move |_, _, cx| { + model.update(cx, |this, cx| { this.respond_to_notification( notification.clone(), true, @@ -344,7 +360,7 @@ impl NotificationPanel { fn present_notification( &self, entry: &NotificationEntry, - cx: &AppContext, + cx: &App, ) -> Option { let user_store = self.user_store.read(cx); let channel_store = self.channel_store.read(cx); @@ -415,7 +431,8 @@ impl NotificationPanel { &mut self, notification_id: u64, notification: &Notification, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let should_mark_as_read = match notification { Notification::ContactRequestAccepted { .. } => true, @@ -429,7 +446,7 @@ impl NotificationPanel { .entry(notification_id) .or_insert_with(|| { let client = self.client.clone(); - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { cx.background_executor().timer(MARK_AS_READ_DELAY).await; client .request(proto::MarkNotificationRead { notification_id }) @@ -443,7 +460,12 @@ impl NotificationPanel { } } - fn did_click_notification(&mut self, notification: &Notification, cx: &mut ViewContext) { + fn did_click_notification( + &mut self, + notification: &Notification, + window: &mut Window, + cx: &mut Context, + ) { if let Notification::ChannelMessageMention { message_id, channel_id, @@ -451,9 +473,9 @@ impl NotificationPanel { } = notification.clone() { if let Some(workspace) = self.workspace.upgrade() { - cx.window_context().defer(move |cx| { + window.defer(cx, move |window, cx| { workspace.update(cx, |workspace, cx| { - if let Some(panel) = workspace.focus_panel::(cx) { + if let Some(panel) = workspace.focus_panel::(window, cx) { panel.update(cx, |panel, cx| { panel .select_channel(ChannelId(channel_id), Some(message_id), cx) @@ -466,7 +488,7 @@ impl NotificationPanel { } } - fn is_showing_notification(&self, notification: &Notification, cx: &ViewContext) -> bool { + fn is_showing_notification(&self, notification: &Notification, cx: &mut Context) -> bool { if !self.active { return false; } @@ -490,16 +512,17 @@ impl NotificationPanel { fn on_notification_event( &mut self, - _: Model, + _: &Entity, event: &NotificationEvent, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { match event { NotificationEvent::NewNotification { entry } => { if !self.is_showing_notification(&entry.notification, cx) { self.unseen_notifications.push(entry.clone()); } - self.add_toast(entry, cx); + self.add_toast(entry, window, cx); } NotificationEvent::NotificationRemoved { entry } | NotificationEvent::NotificationRead { entry } => { @@ -516,7 +539,12 @@ impl NotificationPanel { } } - fn add_toast(&mut self, entry: &NotificationEntry, cx: &mut ViewContext) { + fn add_toast( + &mut self, + entry: &NotificationEntry, + window: &mut Window, + cx: &mut Context, + ) { if self.is_showing_notification(&entry.notification, cx) { return; } @@ -529,7 +557,7 @@ impl NotificationPanel { let notification_id = entry.id; self.current_notification_toast = Some(( notification_id, - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { cx.background_executor().timer(TOAST_DURATION).await; this.update(&mut cx, |this, cx| this.remove_toast(notification_id, cx)) .ok(); @@ -542,8 +570,8 @@ impl NotificationPanel { workspace.dismiss_notification(&id, cx); workspace.show_notification(id, cx, |cx| { - let workspace = cx.view().downgrade(); - cx.new_view(|_| NotificationToast { + let workspace = cx.model().downgrade(); + cx.new(|_| NotificationToast { notification_id, actor, text, @@ -554,7 +582,7 @@ impl NotificationPanel { .ok(); } - fn remove_toast(&mut self, notification_id: u64, cx: &mut ViewContext) { + fn remove_toast(&mut self, notification_id: u64, cx: &mut Context) { if let Some((current_id, _)) = &self.current_notification_toast { if *current_id == notification_id { self.current_notification_toast.take(); @@ -572,7 +600,8 @@ impl NotificationPanel { &mut self, notification: Notification, response: bool, - cx: &mut ViewContext, + + cx: &mut Context, ) { self.notification_store.update(cx, |store, cx| { store.respond_to_notification(notification, response, cx); @@ -581,7 +610,7 @@ impl NotificationPanel { } impl Render for NotificationPanel { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { v_flex() .size_full() .child( @@ -611,15 +640,16 @@ impl Render for NotificationPanel { .full_width() .on_click({ let client = self.client.clone(); - move |_, cx| { + move |_, window, cx| { let client = client.clone(); - cx.spawn(move |cx| async move { - client - .authenticate_and_connect(true, &cx) - .log_err() - .await; - }) - .detach() + window + .spawn(cx, move |cx| async move { + client + .authenticate_and_connect(true, &cx) + .log_err() + .await; + }) + .detach() } }), ) @@ -648,8 +678,8 @@ impl Render for NotificationPanel { } } -impl FocusableView for NotificationPanel { - fn focus_handle(&self, _: &AppContext) -> FocusHandle { +impl Focusable for NotificationPanel { + fn focus_handle(&self, _: &App) -> FocusHandle { self.focus_handle.clone() } } @@ -662,7 +692,7 @@ impl Panel for NotificationPanel { "NotificationPanel" } - fn position(&self, cx: &WindowContext) -> DockPosition { + fn position(&self, _: &Window, cx: &App) -> DockPosition { NotificationPanelSettings::get_global(cx).dock } @@ -670,7 +700,7 @@ impl Panel for NotificationPanel { matches!(position, DockPosition::Left | DockPosition::Right) } - fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext) { + fn set_position(&mut self, position: DockPosition, _: &mut Window, cx: &mut Context) { settings::update_settings_file::( self.fs.clone(), cx, @@ -678,18 +708,18 @@ impl Panel for NotificationPanel { ); } - fn size(&self, cx: &WindowContext) -> Pixels { + fn size(&self, _: &Window, cx: &App) -> Pixels { self.width .unwrap_or_else(|| NotificationPanelSettings::get_global(cx).default_width) } - fn set_size(&mut self, size: Option, cx: &mut ViewContext) { + fn set_size(&mut self, size: Option, _: &mut Window, cx: &mut Context) { self.width = size; self.serialize(cx); cx.notify(); } - fn set_active(&mut self, active: bool, cx: &mut ViewContext) { + fn set_active(&mut self, active: bool, _: &mut Window, cx: &mut Context) { self.active = active; if self.active { @@ -702,7 +732,7 @@ impl Panel for NotificationPanel { } } - fn icon(&self, cx: &WindowContext) -> Option { + fn icon(&self, _: &Window, cx: &App) -> Option { let show_button = NotificationPanelSettings::get_global(cx).button; if !show_button { return None; @@ -715,11 +745,11 @@ impl Panel for NotificationPanel { Some(IconName::BellDot) } - fn icon_tooltip(&self, _cx: &WindowContext) -> Option<&'static str> { + fn icon_tooltip(&self, _window: &Window, _cx: &App) -> Option<&'static str> { Some("Notification Panel") } - fn icon_label(&self, cx: &WindowContext) -> Option { + fn icon_label(&self, _window: &Window, cx: &App) -> Option { let count = self.notification_store.read(cx).unread_notification_count(); if count == 0 { None @@ -741,21 +771,25 @@ pub struct NotificationToast { notification_id: u64, actor: Option>, text: String, - workspace: WeakView, + workspace: WeakEntity, } impl NotificationToast { - fn focus_notification_panel(&self, cx: &mut ViewContext) { + fn focus_notification_panel(&self, window: &mut Window, cx: &mut Context) { let workspace = self.workspace.clone(); let notification_id = self.notification_id; - cx.window_context().defer(move |cx| { + window.defer(cx, move |window, cx| { workspace .update(cx, |workspace, cx| { - if let Some(panel) = workspace.focus_panel::(cx) { + if let Some(panel) = workspace.focus_panel::(window, cx) { panel.update(cx, |panel, cx| { let store = panel.notification_store.read(cx); if let Some(entry) = store.notification_for_id(notification_id) { - panel.did_click_notification(&entry.clone().notification, cx); + panel.did_click_notification( + &entry.clone().notification, + window, + cx, + ); } }); } @@ -766,7 +800,7 @@ impl NotificationToast { } impl Render for NotificationToast { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { let user = self.actor.clone(); h_flex() @@ -778,10 +812,10 @@ impl Render for NotificationToast { .child(Label::new(self.text.clone())) .child( IconButton::new("close", IconName::Close) - .on_click(cx.listener(|_, _, cx| cx.emit(DismissEvent))), + .on_click(cx.listener(|_, _, _, cx| cx.emit(DismissEvent))), ) - .on_click(cx.listener(|this, _, cx| { - this.focus_notification_panel(cx); + .on_click(cx.listener(|this, _, window, cx| { + this.focus_notification_panel(window, cx); cx.emit(DismissEvent); })) } diff --git a/crates/collab_ui/src/notifications.rs b/crates/collab_ui/src/notifications.rs index 7759fef520..f5597895dd 100644 --- a/crates/collab_ui/src/notifications.rs +++ b/crates/collab_ui/src/notifications.rs @@ -5,14 +5,14 @@ pub mod project_shared_notification; #[cfg(feature = "stories")] mod stories; -use gpui::AppContext; +use gpui::App; use std::sync::Arc; use workspace::AppState; #[cfg(feature = "stories")] pub use stories::*; -pub fn init(app_state: &Arc, cx: &mut AppContext) { +pub fn init(app_state: &Arc, cx: &mut App) { incoming_call_notification::init(app_state, cx); project_shared_notification::init(app_state, cx); } diff --git a/crates/collab_ui/src/notifications/collab_notification.rs b/crates/collab_ui/src/notifications/collab_notification.rs index 14dae9cd2c..6b2c5dd045 100644 --- a/crates/collab_ui/src/notifications/collab_notification.rs +++ b/crates/collab_ui/src/notifications/collab_notification.rs @@ -32,7 +32,7 @@ impl ParentElement for CollabNotification { } impl RenderOnce for CollabNotification { - fn render(self, cx: &mut WindowContext) -> impl IntoElement { + fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement { h_flex() .text_ui(cx) .justify_between() diff --git a/crates/collab_ui/src/notifications/incoming_call_notification.rs b/crates/collab_ui/src/notifications/incoming_call_notification.rs index cca67cb5e7..1ee4fd480f 100644 --- a/crates/collab_ui/src/notifications/incoming_call_notification.rs +++ b/crates/collab_ui/src/notifications/incoming_call_notification.rs @@ -2,14 +2,14 @@ use crate::notification_window_options; use crate::notifications::collab_notification::CollabNotification; use call::{ActiveCall, IncomingCall}; use futures::StreamExt; -use gpui::{prelude::*, AppContext, WindowHandle}; +use gpui::{prelude::*, App, WindowHandle}; use std::sync::{Arc, Weak}; use ui::{prelude::*, Button, Label}; use util::ResultExt; use workspace::AppState; -pub fn init(app_state: &Arc, cx: &mut AppContext) { +pub fn init(app_state: &Arc, cx: &mut App) { let app_state = Arc::downgrade(app_state); let mut incoming_call = ActiveCall::global(cx).read(cx).incoming(); cx.spawn(|mut cx| async move { @@ -17,8 +17,8 @@ pub fn init(app_state: &Arc, cx: &mut AppContext) { while let Some(incoming_call) = incoming_call.next().await { for window in notification_windows.drain(..) { window - .update(&mut cx, |_, cx| { - cx.remove_window(); + .update(&mut cx, |_, window, _| { + window.remove_window(); }) .log_err(); } @@ -36,8 +36,8 @@ pub fn init(app_state: &Arc, cx: &mut AppContext) { .log_err() { let window = cx - .open_window(options, |cx| { - cx.new_view(|_| { + .open_window(options, |_, cx| { + cx.new(|_| { IncomingCallNotification::new( incoming_call.clone(), app_state.clone(), @@ -67,14 +67,14 @@ impl IncomingCallNotificationState { Self { call, app_state } } - fn respond(&self, accept: bool, cx: &mut AppContext) { + fn respond(&self, accept: bool, cx: &mut App) { let active_call = ActiveCall::global(cx); if accept { let join = active_call.update(cx, |active_call, cx| active_call.accept_incoming(cx)); let caller_user_id = self.call.calling_user.id; let initial_project_id = self.call.initial_project.as_ref().map(|project| project.id); let app_state = self.app_state.clone(); - let cx: &mut AppContext = cx; + let cx: &mut App = cx; cx.spawn(|cx| async move { join.await?; if let Some(project_id) = initial_project_id { @@ -111,19 +111,19 @@ impl IncomingCallNotification { } impl Render for IncomingCallNotification { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { - let ui_font = theme::setup_ui_font(cx); + fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { + let ui_font = theme::setup_ui_font(window, cx); div().size_full().font(ui_font).child( CollabNotification::new( self.state.call.calling_user.avatar_uri.clone(), Button::new("accept", "Accept").on_click({ let state = self.state.clone(); - move |_, cx| state.respond(true, cx) + move |_, _, cx| state.respond(true, cx) }), Button::new("decline", "Decline").on_click({ let state = self.state.clone(); - move |_, cx| state.respond(false, cx) + move |_, _, cx| state.respond(false, cx) }), ) .child(v_flex().overflow_hidden().child(Label::new(format!( diff --git a/crates/collab_ui/src/notifications/project_shared_notification.rs b/crates/collab_ui/src/notifications/project_shared_notification.rs index 4a55799674..d5880dc4b9 100644 --- a/crates/collab_ui/src/notifications/project_shared_notification.rs +++ b/crates/collab_ui/src/notifications/project_shared_notification.rs @@ -3,14 +3,14 @@ use crate::notifications::collab_notification::CollabNotification; use call::{room, ActiveCall}; use client::User; use collections::HashMap; -use gpui::{AppContext, Size}; +use gpui::{App, Size}; use std::sync::{Arc, Weak}; use ui::{prelude::*, Button, Label}; use util::ResultExt; use workspace::AppState; -pub fn init(app_state: &Arc, cx: &mut AppContext) { +pub fn init(app_state: &Arc, cx: &mut App) { let app_state = Arc::downgrade(app_state); let active_call = ActiveCall::global(cx); let mut notification_windows = HashMap::default(); @@ -28,8 +28,8 @@ pub fn init(app_state: &Arc, cx: &mut AppContext) { for screen in cx.displays() { let options = notification_window_options(screen, window_size, cx); let Some(window) = cx - .open_window(options, |cx| { - cx.new_view(|_| { + .open_window(options, |_, cx| { + cx.new(|_| { ProjectSharedNotification::new( owner.clone(), *project_id, @@ -55,8 +55,8 @@ pub fn init(app_state: &Arc, cx: &mut AppContext) { if let Some(windows) = notification_windows.remove(project_id) { for window in windows { window - .update(cx, |_, cx| { - cx.remove_window(); + .update(cx, |_, window, _| { + window.remove_window(); }) .ok(); } @@ -67,8 +67,8 @@ pub fn init(app_state: &Arc, cx: &mut AppContext) { for (_, windows) in notification_windows.drain() { for window in windows { window - .update(cx, |_, cx| { - cx.remove_window(); + .update(cx, |_, window, _| { + window.remove_window(); }) .ok(); } @@ -101,14 +101,14 @@ impl ProjectSharedNotification { } } - fn join(&mut self, cx: &mut ViewContext) { + fn join(&mut self, cx: &mut Context) { if let Some(app_state) = self.app_state.upgrade() { workspace::join_in_room_project(self.project_id, self.owner.id, app_state, cx) .detach_and_log_err(cx); } } - fn dismiss(&mut self, cx: &mut ViewContext) { + fn dismiss(&mut self, cx: &mut Context) { if let Some(active_room) = ActiveCall::global(cx).read_with(cx, |call, _| call.room().cloned()) { @@ -122,18 +122,20 @@ impl ProjectSharedNotification { } impl Render for ProjectSharedNotification { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { - let ui_font = theme::setup_ui_font(cx); + fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { + let ui_font = theme::setup_ui_font(window, cx); div().size_full().font(ui_font).child( CollabNotification::new( self.owner.avatar_uri.clone(), - Button::new("open", "Open").on_click(cx.listener(move |this, _event, cx| { + Button::new("open", "Open").on_click(cx.listener(move |this, _event, _, cx| { this.join(cx); })), - Button::new("dismiss", "Dismiss").on_click(cx.listener(move |this, _event, cx| { - this.dismiss(cx); - })), + Button::new("dismiss", "Dismiss").on_click(cx.listener( + move |this, _event, _, cx| { + this.dismiss(cx); + }, + )), ) .child(Label::new(self.owner.github_login.clone())) .child(Label::new(format!( diff --git a/crates/collab_ui/src/notifications/stories/collab_notification.rs b/crates/collab_ui/src/notifications/stories/collab_notification.rs index c70837444b..ca939bcda7 100644 --- a/crates/collab_ui/src/notifications/stories/collab_notification.rs +++ b/crates/collab_ui/src/notifications/stories/collab_notification.rs @@ -7,7 +7,7 @@ use crate::notifications::collab_notification::CollabNotification; pub struct CollabNotificationStory; impl Render for CollabNotificationStory { - fn render(&mut self, _cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { let window_container = |width, height| div().w(px(width)).h(px(height)); Story::container() diff --git a/crates/collab_ui/src/panel_settings.rs b/crates/collab_ui/src/panel_settings.rs index 06c43b5611..3133894d80 100644 --- a/crates/collab_ui/src/panel_settings.rs +++ b/crates/collab_ui/src/panel_settings.rs @@ -126,7 +126,7 @@ impl Settings for CollaborationPanelSettings { fn load( sources: SettingsSources, - _: &mut gpui::AppContext, + _: &mut gpui::App, ) -> anyhow::Result { sources.json_merge() } @@ -139,7 +139,7 @@ impl Settings for ChatPanelSettings { fn load( sources: SettingsSources, - _: &mut gpui::AppContext, + _: &mut gpui::App, ) -> anyhow::Result { sources.json_merge() } @@ -152,7 +152,7 @@ impl Settings for NotificationPanelSettings { fn load( sources: SettingsSources, - _: &mut gpui::AppContext, + _: &mut gpui::App, ) -> anyhow::Result { sources.json_merge() } @@ -165,7 +165,7 @@ impl Settings for MessageEditorSettings { fn load( sources: SettingsSources, - _: &mut gpui::AppContext, + _: &mut gpui::App, ) -> anyhow::Result { sources.json_merge() } diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index ce0c36300e..2675d244c6 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/crates/command_palette/src/command_palette.rs @@ -11,8 +11,8 @@ use command_palette_hooks::{ }; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ - Action, AppContext, DismissEvent, EventEmitter, FocusHandle, FocusableView, Global, - ParentElement, Render, Styled, Task, UpdateGlobal, View, ViewContext, VisualContext, WeakView, + Action, App, Context, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, Global, + ParentElement, Render, Styled, Task, UpdateGlobal, WeakEntity, Window, }; use picker::{Picker, PickerDelegate}; use postage::{sink::Sink, stream::Stream}; @@ -22,17 +22,17 @@ use util::ResultExt; use workspace::{ModalView, Workspace, WorkspaceSettings}; use zed_actions::{command_palette::Toggle, OpenZedUrl}; -pub fn init(cx: &mut AppContext) { +pub fn init(cx: &mut App) { client::init_settings(cx); cx.set_global(HitCounts::default()); command_palette_hooks::init(cx); - cx.observe_new_views(CommandPalette::register).detach(); + cx.observe_new(CommandPalette::register).detach(); } impl ModalView for CommandPalette {} pub struct CommandPalette { - picker: View>, + picker: Entity>, } /// Removes subsequent whitespace characters and double colons from the query. @@ -59,24 +59,40 @@ fn normalize_query(input: &str) -> String { } impl CommandPalette { - fn register(workspace: &mut Workspace, _: &mut ViewContext) { - workspace.register_action(|workspace, _: &Toggle, cx| Self::toggle(workspace, "", cx)); - } - - pub fn toggle(workspace: &mut Workspace, query: &str, cx: &mut ViewContext) { - let Some(previous_focus_handle) = cx.focused() else { - return; - }; - workspace.toggle_modal(cx, move |cx| { - CommandPalette::new(previous_focus_handle, query, cx) + fn register( + workspace: &mut Workspace, + _window: Option<&mut Window>, + _: &mut Context, + ) { + workspace.register_action(|workspace, _: &Toggle, window, cx| { + Self::toggle(workspace, "", window, cx) }); } - fn new(previous_focus_handle: FocusHandle, query: &str, cx: &mut ViewContext) -> Self { + pub fn toggle( + workspace: &mut Workspace, + query: &str, + window: &mut Window, + cx: &mut Context, + ) { + let Some(previous_focus_handle) = window.focused(cx) else { + return; + }; + workspace.toggle_modal(window, cx, move |window, cx| { + CommandPalette::new(previous_focus_handle, query, window, cx) + }); + } + + fn new( + previous_focus_handle: FocusHandle, + query: &str, + window: &mut Window, + cx: &mut Context, + ) -> Self { let filter = CommandPaletteFilter::try_global(cx); - let commands = cx - .available_actions() + let commands = window + .available_actions(cx) .into_iter() .filter_map(|action| { if filter.is_some_and(|filter| filter.is_hidden(&*action)) { @@ -91,38 +107,38 @@ impl CommandPalette { .collect(); let delegate = - CommandPaletteDelegate::new(cx.view().downgrade(), commands, previous_focus_handle); + CommandPaletteDelegate::new(cx.model().downgrade(), commands, previous_focus_handle); - let picker = cx.new_view(|cx| { - let picker = Picker::uniform_list(delegate, cx); - picker.set_query(query, cx); + let picker = cx.new(|cx| { + let picker = Picker::uniform_list(delegate, window, cx); + picker.set_query(query, window, cx); picker }); Self { picker } } - pub fn set_query(&mut self, query: &str, cx: &mut ViewContext) { + pub fn set_query(&mut self, query: &str, window: &mut Window, cx: &mut Context) { self.picker - .update(cx, |picker, cx| picker.set_query(query, cx)) + .update(cx, |picker, cx| picker.set_query(query, window, cx)) } } impl EventEmitter for CommandPalette {} -impl FocusableView for CommandPalette { - fn focus_handle(&self, cx: &AppContext) -> FocusHandle { +impl Focusable for CommandPalette { + fn focus_handle(&self, cx: &App) -> FocusHandle { self.picker.focus_handle(cx) } } impl Render for CommandPalette { - fn render(&mut self, _cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { v_flex().w(rems(34.)).child(self.picker.clone()) } } pub struct CommandPaletteDelegate { - command_palette: WeakView, + command_palette: WeakEntity, all_commands: Vec, commands: Vec, matches: Vec, @@ -158,7 +174,7 @@ impl Global for HitCounts {} impl CommandPaletteDelegate { fn new( - command_palette: WeakView, + command_palette: WeakEntity, commands: Vec, previous_focus_handle: FocusHandle, ) -> Self { @@ -178,7 +194,7 @@ impl CommandPaletteDelegate { query: String, mut commands: Vec, mut matches: Vec, - cx: &mut ViewContext>, + cx: &mut Context>, ) { self.updating_matches.take(); @@ -232,7 +248,7 @@ impl CommandPaletteDelegate { impl PickerDelegate for CommandPaletteDelegate { type ListItem = ListItem; - fn placeholder_text(&self, _cx: &mut WindowContext) -> Arc { + fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc { "Execute a command...".into() } @@ -244,14 +260,20 @@ impl PickerDelegate for CommandPaletteDelegate { self.selected_ix } - fn set_selected_index(&mut self, ix: usize, _: &mut ViewContext>) { + fn set_selected_index( + &mut self, + ix: usize, + _window: &mut Window, + _: &mut Context>, + ) { self.selected_ix = ix; } fn update_matches( &mut self, mut query: String, - cx: &mut ViewContext>, + window: &mut Window, + cx: &mut Context>, ) -> gpui::Task<()> { let settings = WorkspaceSettings::get_global(cx); if let Some(alias) = settings.command_aliases.get(&query) { @@ -304,7 +326,7 @@ impl PickerDelegate for CommandPaletteDelegate { }); self.updating_matches = Some((task, rx.clone())); - cx.spawn(move |picker, mut cx| async move { + cx.spawn_in(window, move |picker, mut cx| async move { let Some((commands, matches)) = rx.recv().await else { return; }; @@ -323,7 +345,8 @@ impl PickerDelegate for CommandPaletteDelegate { &mut self, query: String, duration: Duration, - cx: &mut ViewContext>, + _: &mut Window, + cx: &mut Context>, ) -> bool { let Some((task, rx)) = self.updating_matches.take() else { return true; @@ -344,20 +367,19 @@ impl PickerDelegate for CommandPaletteDelegate { } } - fn dismissed(&mut self, cx: &mut ViewContext>) { + fn dismissed(&mut self, _window: &mut Window, cx: &mut Context>) { self.command_palette .update(cx, |_, cx| cx.emit(DismissEvent)) .log_err(); } - fn confirm(&mut self, _: bool, cx: &mut ViewContext>) { + fn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context>) { if self.matches.is_empty() { - self.dismissed(cx); + self.dismissed(window, cx); return; } let action_ix = self.matches[self.selected_ix].candidate_id; let command = self.commands.swap_remove(action_ix); - telemetry::event!( "Action Invoked", source = "command palette", @@ -369,16 +391,17 @@ impl PickerDelegate for CommandPaletteDelegate { *hit_counts.0.entry(command.name).or_default() += 1; }); let action = command.action; - cx.focus(&self.previous_focus_handle); - self.dismissed(cx); - cx.dispatch_action(action); + window.focus(&self.previous_focus_handle); + self.dismissed(window, cx); + window.dispatch_action(action, cx); } fn render_match( &self, ix: usize, selected: bool, - cx: &mut ViewContext>, + window: &mut Window, + _: &mut Context>, ) -> Option { let r#match = self.matches.get(ix)?; let command = self.commands.get(r#match.candidate_id)?; @@ -399,7 +422,7 @@ impl PickerDelegate for CommandPaletteDelegate { .children(KeyBinding::for_action_in( &*command.action, &self.previous_focus_handle, - cx, + window, )), ), ) @@ -490,17 +513,18 @@ mod tests { async fn test_command_palette(cx: &mut TestAppContext) { let app_state = init_test(cx); let project = Project::test(app_state.fs.clone(), [], cx).await; - let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx)); + let (workspace, cx) = + cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx)); - let editor = cx.new_view(|cx| { - let mut editor = Editor::single_line(cx); - editor.set_text("abc", cx); + let editor = cx.new_window_model(|window, cx| { + let mut editor = Editor::single_line(window, cx); + editor.set_text("abc", window, cx); editor }); - workspace.update(cx, |workspace, cx| { - workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, cx); - editor.update(cx, |editor, cx| editor.focus(cx)) + workspace.update_in(cx, |workspace, window, cx| { + workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx); + editor.update(cx, |editor, cx| window.focus(&editor.focus_handle(cx))) }); cx.simulate_keystrokes("cmd-shift-p"); @@ -535,7 +559,7 @@ mod tests { }); // Add namespace filter, and redeploy the palette - cx.update(|cx| { + cx.update(|_window, cx| { CommandPaletteFilter::update_global(cx, |filter, _| { filter.hide_namespace("editor"); }); @@ -560,17 +584,18 @@ mod tests { async fn test_normalized_matches(cx: &mut TestAppContext) { let app_state = init_test(cx); let project = Project::test(app_state.fs.clone(), [], cx).await; - let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx)); + let (workspace, cx) = + cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx)); - let editor = cx.new_view(|cx| { - let mut editor = Editor::single_line(cx); - editor.set_text("abc", cx); + let editor = cx.new_window_model(|window, cx| { + let mut editor = Editor::single_line(window, cx); + editor.set_text("abc", window, cx); editor }); - workspace.update(cx, |workspace, cx| { - workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, cx); - editor.update(cx, |editor, cx| editor.focus(cx)) + workspace.update_in(cx, |workspace, window, cx| { + workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx); + editor.update(cx, |editor, cx| window.focus(&editor.focus_handle(cx))) }); // Test normalize (trimming whitespace and double colons) @@ -595,14 +620,17 @@ mod tests { async fn test_go_to_line(cx: &mut TestAppContext) { let app_state = init_test(cx); let project = Project::test(app_state.fs.clone(), [], cx).await; - let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx)); + let (workspace, cx) = + cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx)); cx.simulate_keystrokes("cmd-n"); let editor = workspace.update(cx, |workspace, cx| { workspace.active_item_as::(cx).unwrap() }); - editor.update(cx, |editor, cx| editor.set_text("1\n2\n3\n4\n5\n6\n", cx)); + editor.update_in(cx, |editor, window, cx| { + editor.set_text("1\n2\n3\n4\n5\n6\n", window, cx) + }); cx.simulate_keystrokes("cmd-shift-p"); cx.simulate_input("go to line: Toggle"); @@ -614,8 +642,8 @@ mod tests { cx.simulate_keystrokes("3 enter"); - editor.update(cx, |editor, cx| { - assert!(editor.focus_handle(cx).is_focused(cx)); + editor.update_in(cx, |editor, window, cx| { + assert!(editor.focus_handle(cx).is_focused(window)); assert_eq!( editor.selections.last::(cx).range().start, Point::new(2, 0) diff --git a/crates/command_palette_hooks/src/command_palette_hooks.rs b/crates/command_palette_hooks/src/command_palette_hooks.rs index e113fe59ca..3ea94bd10f 100644 --- a/crates/command_palette_hooks/src/command_palette_hooks.rs +++ b/crates/command_palette_hooks/src/command_palette_hooks.rs @@ -6,10 +6,10 @@ use std::any::TypeId; use collections::HashSet; use derive_more::{Deref, DerefMut}; -use gpui::{Action, AppContext, BorrowAppContext, Global}; +use gpui::{Action, App, BorrowAppContext, Global}; /// Initializes the command palette hooks. -pub fn init(cx: &mut AppContext) { +pub fn init(cx: &mut App) { cx.set_global(GlobalCommandPaletteFilter::default()); cx.set_global(GlobalCommandPaletteInterceptor::default()); } @@ -31,20 +31,20 @@ impl Global for GlobalCommandPaletteFilter {} impl CommandPaletteFilter { /// Returns the global [`CommandPaletteFilter`], if one is set. - pub fn try_global(cx: &AppContext) -> Option<&CommandPaletteFilter> { + pub fn try_global(cx: &App) -> Option<&CommandPaletteFilter> { cx.try_global::() .map(|filter| &filter.0) } /// Returns a mutable reference to the global [`CommandPaletteFilter`]. - pub fn global_mut(cx: &mut AppContext) -> &mut Self { + pub fn global_mut(cx: &mut App) -> &mut Self { cx.global_mut::() } /// Updates the global [`CommandPaletteFilter`] using the given closure. - pub fn update_global(cx: &mut AppContext, update: F) + pub fn update_global(cx: &mut App, update: F) where - F: FnOnce(&mut Self, &mut AppContext), + F: FnOnce(&mut Self, &mut App), { if cx.has_global::() { cx.update_global(|this: &mut GlobalCommandPaletteFilter, cx| update(&mut this.0, cx)) @@ -93,6 +93,7 @@ impl CommandPaletteFilter { } /// The result of intercepting a command palette command. +#[derive(Debug)] pub struct CommandInterceptResult { /// The action produced as a result of the interception. pub action: Box, @@ -107,7 +108,7 @@ pub struct CommandInterceptResult { /// An interceptor for the command palette. #[derive(Default)] pub struct CommandPaletteInterceptor( - Option Option>>, + Option Option>>, ); #[derive(Default)] @@ -117,21 +118,21 @@ impl Global for GlobalCommandPaletteInterceptor {} impl CommandPaletteInterceptor { /// Returns the global [`CommandPaletteInterceptor`], if one is set. - pub fn try_global(cx: &AppContext) -> Option<&CommandPaletteInterceptor> { + pub fn try_global(cx: &App) -> Option<&CommandPaletteInterceptor> { cx.try_global::() .map(|interceptor| &interceptor.0) } /// Updates the global [`CommandPaletteInterceptor`] using the given closure. - pub fn update_global(cx: &mut AppContext, update: F) -> R + pub fn update_global(cx: &mut App, update: F) -> R where - F: FnOnce(&mut Self, &mut AppContext) -> R, + F: FnOnce(&mut Self, &mut App) -> R, { cx.update_global(|this: &mut GlobalCommandPaletteInterceptor, cx| update(&mut this.0, cx)) } /// Intercepts the given query from the command palette. - pub fn intercept(&self, query: &str, cx: &AppContext) -> Option { + pub fn intercept(&self, query: &str, cx: &App) -> Option { let handler = self.0.as_ref()?; (handler)(query, cx) @@ -145,10 +146,7 @@ impl CommandPaletteInterceptor { /// Sets the global interceptor. /// /// This will override the previous interceptor, if it exists. - pub fn set( - &mut self, - handler: Box Option>, - ) { + pub fn set(&mut self, handler: Box Option>) { self.0 = Some(handler); } } diff --git a/crates/context_server/src/client.rs b/crates/context_server/src/client.rs index 64aabb00e8..2a9236dd28 100644 --- a/crates/context_server/src/client.rs +++ b/crates/context_server/src/client.rs @@ -1,4 +1,4 @@ -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, Context as _, Result}; use collections::HashMap; use futures::{channel::oneshot, io::BufWriter, select, AsyncRead, AsyncWrite, FutureExt}; use gpui::{AsyncAppContext, BackgroundExecutor, Task}; diff --git a/crates/context_server/src/context_server.rs b/crates/context_server/src/context_server.rs index 84c08d7b2a..6189ea4e82 100644 --- a/crates/context_server/src/context_server.rs +++ b/crates/context_server/src/context_server.rs @@ -8,7 +8,7 @@ pub mod types; use command_palette_hooks::CommandPaletteFilter; pub use context_server_settings::{ContextServerSettings, ServerCommand, ServerConfig}; -use gpui::{actions, AppContext}; +use gpui::{actions, App}; pub use crate::context_server_tool::ContextServerTool; pub use crate::registry::ContextServerFactoryRegistry; @@ -18,7 +18,7 @@ actions!(context_servers, [Restart]); /// The namespace for the context servers actions. pub const CONTEXT_SERVERS_NAMESPACE: &'static str = "context_servers"; -pub fn init(cx: &mut AppContext) { +pub fn init(cx: &mut App) { context_server_settings::init(cx); ContextServerFactoryRegistry::default_global(cx); extension_context_server::init(cx); diff --git a/crates/context_server/src/context_server_tool.rs b/crates/context_server/src/context_server_tool.rs index 161b61b22f..d91c8e2e64 100644 --- a/crates/context_server/src/context_server_tool.rs +++ b/crates/context_server/src/context_server_tool.rs @@ -2,20 +2,20 @@ use std::sync::Arc; use anyhow::{anyhow, bail}; use assistant_tool::Tool; -use gpui::{Model, Task, WindowContext}; +use gpui::{App, Entity, Task, Window}; use crate::manager::ContextServerManager; use crate::types; pub struct ContextServerTool { - server_manager: Model, + server_manager: Entity, server_id: Arc, tool: types::Tool, } impl ContextServerTool { pub fn new( - server_manager: Model, + server_manager: Entity, server_id: impl Into>, tool: types::Tool, ) -> Self { @@ -51,8 +51,9 @@ impl Tool for ContextServerTool { fn run( self: std::sync::Arc, input: serde_json::Value, - _workspace: gpui::WeakView, - cx: &mut WindowContext, + _workspace: gpui::WeakEntity, + _: &mut Window, + cx: &mut App, ) -> gpui::Task> { if let Some(server) = self.server_manager.read(cx).get_server(&self.server_id) { cx.foreground_executor().spawn({ diff --git a/crates/context_server/src/extension_context_server.rs b/crates/context_server/src/extension_context_server.rs index 36fecd2af3..efbbc6d594 100644 --- a/crates/context_server/src/extension_context_server.rs +++ b/crates/context_server/src/extension_context_server.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use extension::{Extension, ExtensionContextServerProxy, ExtensionHostProxy, ProjectDelegate}; -use gpui::{AppContext, Model}; +use gpui::{App, Entity}; use crate::{ContextServerFactoryRegistry, ServerCommand}; @@ -15,7 +15,7 @@ impl ProjectDelegate for ExtensionProject { } } -pub fn init(cx: &mut AppContext) { +pub fn init(cx: &mut App) { let proxy = ExtensionHostProxy::default_global(cx); proxy.register_context_server_proxy(ContextServerFactoryRegistryProxy { context_server_factory_registry: ContextServerFactoryRegistry::global(cx), @@ -23,16 +23,11 @@ pub fn init(cx: &mut AppContext) { } struct ContextServerFactoryRegistryProxy { - context_server_factory_registry: Model, + context_server_factory_registry: Entity, } impl ExtensionContextServerProxy for ContextServerFactoryRegistryProxy { - fn register_context_server( - &self, - extension: Arc, - id: Arc, - cx: &mut AppContext, - ) { + fn register_context_server(&self, extension: Arc, id: Arc, cx: &mut App) { self.context_server_factory_registry .update(cx, |registry, _| { registry.register_server_factory( diff --git a/crates/context_server/src/manager.rs b/crates/context_server/src/manager.rs index febbee1cdf..3017a19f4a 100644 --- a/crates/context_server/src/manager.rs +++ b/crates/context_server/src/manager.rs @@ -20,7 +20,7 @@ use std::sync::Arc; use anyhow::{bail, Result}; use collections::HashMap; use command_palette_hooks::CommandPaletteFilter; -use gpui::{AsyncAppContext, EventEmitter, Model, ModelContext, Subscription, Task, WeakModel}; +use gpui::{AsyncAppContext, Context, Entity, EventEmitter, Subscription, Task, WeakEntity}; use log; use parking_lot::RwLock; use project::Project; @@ -104,8 +104,8 @@ impl ContextServer { pub struct ContextServerManager { servers: HashMap, Arc>, - project: Model, - registry: Model, + project: Entity, + registry: Entity, update_servers_task: Option>>, needs_server_update: bool, _subscriptions: Vec, @@ -120,9 +120,9 @@ impl EventEmitter for ContextServerManager {} impl ContextServerManager { pub fn new( - registry: Model, - project: Model, - cx: &mut ModelContext, + registry: Entity, + project: Entity, + cx: &mut Context, ) -> Self { let mut this = Self { _subscriptions: vec![ @@ -143,7 +143,7 @@ impl ContextServerManager { this } - fn available_context_servers_changed(&mut self, cx: &mut ModelContext) { + fn available_context_servers_changed(&mut self, cx: &mut Context) { if self.update_servers_task.is_some() { self.needs_server_update = true; } else { @@ -183,7 +183,7 @@ impl ContextServerManager { pub fn restart_server( &mut self, id: &Arc, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { let id = id.clone(); cx.spawn(|this, mut cx| async move { @@ -214,7 +214,7 @@ impl ContextServerManager { .collect() } - async fn maintain_servers(this: WeakModel, mut cx: AsyncAppContext) -> Result<()> { + async fn maintain_servers(this: WeakEntity, mut cx: AsyncAppContext) -> Result<()> { let mut desired_servers = HashMap::default(); let (registry, project) = this.update(&mut cx, |this, cx| { diff --git a/crates/context_server/src/registry.rs b/crates/context_server/src/registry.rs index a4d0f9a804..697b6da3ce 100644 --- a/crates/context_server/src/registry.rs +++ b/crates/context_server/src/registry.rs @@ -2,16 +2,19 @@ use std::sync::Arc; use anyhow::Result; use collections::HashMap; -use gpui::{AppContext, AsyncAppContext, Context, Global, Model, ReadGlobal, Task}; +use gpui::{App, AppContext as _, AsyncAppContext, Entity, Global, ReadGlobal, Task}; use project::Project; use crate::ServerCommand; pub type ContextServerFactory = Arc< - dyn Fn(Model, &AsyncAppContext) -> Task> + Send + Sync + 'static, + dyn Fn(Entity, &AsyncAppContext) -> Task> + + Send + + Sync + + 'static, >; -struct GlobalContextServerFactoryRegistry(Model); +struct GlobalContextServerFactoryRegistry(Entity); impl Global for GlobalContextServerFactoryRegistry {} @@ -22,16 +25,16 @@ pub struct ContextServerFactoryRegistry { impl ContextServerFactoryRegistry { /// Returns the global [`ContextServerFactoryRegistry`]. - pub fn global(cx: &AppContext) -> Model { + pub fn global(cx: &App) -> Entity { GlobalContextServerFactoryRegistry::global(cx).0.clone() } /// Returns the global [`ContextServerFactoryRegistry`]. /// /// Inserts a default [`ContextServerFactoryRegistry`] if one does not yet exist. - pub fn default_global(cx: &mut AppContext) -> Model { + pub fn default_global(cx: &mut App) -> Entity { if !cx.has_global::() { - let registry = cx.new_model(|_| Self::new()); + let registry = cx.new(|_| Self::new()); cx.set_global(GlobalContextServerFactoryRegistry(registry)); } cx.global::().0.clone() diff --git a/crates/context_server_settings/src/context_server_settings.rs b/crates/context_server_settings/src/context_server_settings.rs index 68969ca795..d91a15ecfb 100644 --- a/crates/context_server_settings/src/context_server_settings.rs +++ b/crates/context_server_settings/src/context_server_settings.rs @@ -1,14 +1,14 @@ use std::sync::Arc; use collections::HashMap; -use gpui::AppContext; +use gpui::App; use schemars::gen::SchemaGenerator; use schemars::schema::{InstanceType, Schema, SchemaObject}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use settings::{Settings, SettingsSources}; -pub fn init(cx: &mut AppContext) { +pub fn init(cx: &mut App) { ContextServerSettings::register(cx); } @@ -54,7 +54,7 @@ impl Settings for ContextServerSettings { fn load( sources: SettingsSources, - _: &mut gpui::AppContext, + _: &mut gpui::App, ) -> anyhow::Result { sources.json_merge() } diff --git a/crates/copilot/src/copilot.rs b/crates/copilot/src/copilot.rs index 67280765f6..2551a75447 100644 --- a/crates/copilot/src/copilot.rs +++ b/crates/copilot/src/copilot.rs @@ -11,8 +11,8 @@ use collections::{HashMap, HashSet}; use command_palette_hooks::CommandPaletteFilter; use futures::{channel::oneshot, future::Shared, Future, FutureExt, TryFutureExt}; use gpui::{ - actions, AppContext, AsyncAppContext, Context, Entity, EntityId, EventEmitter, Global, Model, - ModelContext, Task, WeakModel, + actions, App, AppContext as _, AsyncAppContext, Context, Entity, EntityId, EventEmitter, + Global, Task, WeakEntity, }; use http_client::github::get_release_by_tag_name; use http_client::HttpClient; @@ -58,11 +58,11 @@ pub fn init( fs: Arc, http: Arc, node_runtime: NodeRuntime, - cx: &mut AppContext, + cx: &mut App, ) { copilot_chat::init(fs, http.clone(), cx); - let copilot = cx.new_model({ + let copilot = cx.new({ let node_runtime = node_runtime.clone(); move |cx| Copilot::start(new_server_id, http, node_runtime, cx) }); @@ -209,8 +209,8 @@ struct RegisteredBuffer { impl RegisteredBuffer { fn report_changes( &mut self, - buffer: &Model, - cx: &mut ModelContext, + buffer: &Entity, + cx: &mut Context, ) -> oneshot::Receiver<(i32, BufferSnapshot)> { let (done_tx, done_rx) = oneshot::channel(); @@ -304,7 +304,7 @@ pub struct Copilot { http: Arc, node_runtime: NodeRuntime, server: CopilotServer, - buffers: HashSet>, + buffers: HashSet>, server_id: LanguageServerId, _subscription: gpui::Subscription, } @@ -317,17 +317,17 @@ pub enum Event { impl EventEmitter for Copilot {} -struct GlobalCopilot(Model); +struct GlobalCopilot(Entity); impl Global for GlobalCopilot {} impl Copilot { - pub fn global(cx: &AppContext) -> Option> { + pub fn global(cx: &App) -> Option> { cx.try_global::() .map(|model| model.0.clone()) } - pub fn set_global(copilot: Model, cx: &mut AppContext) { + pub fn set_global(copilot: Entity, cx: &mut App) { cx.set_global(GlobalCopilot(copilot)); } @@ -335,7 +335,7 @@ impl Copilot { new_server_id: LanguageServerId, http: Arc, node_runtime: NodeRuntime, - cx: &mut ModelContext, + cx: &mut Context, ) -> Self { let mut this = Self { server_id: new_server_id, @@ -351,10 +351,7 @@ impl Copilot { this } - fn shutdown_language_server( - &mut self, - _cx: &mut ModelContext, - ) -> impl Future { + fn shutdown_language_server(&mut self, _cx: &mut Context) -> impl Future { let shutdown = match mem::replace(&mut self.server, CopilotServer::Disabled) { CopilotServer::Running(server) => Some(Box::pin(async move { server.lsp.shutdown() })), _ => None, @@ -367,7 +364,7 @@ impl Copilot { } } - fn enable_or_disable_copilot(&mut self, cx: &mut ModelContext) { + fn enable_or_disable_copilot(&mut self, cx: &mut Context) { let server_id = self.server_id; let http = self.http.clone(); let node_runtime = self.node_runtime.clone(); @@ -390,7 +387,7 @@ impl Copilot { } #[cfg(any(test, feature = "test-support"))] - pub fn fake(cx: &mut gpui::TestAppContext) -> (Model, lsp::FakeLanguageServer) { + pub fn fake(cx: &mut gpui::TestAppContext) -> (Entity, lsp::FakeLanguageServer) { use lsp::FakeLanguageServer; use node_runtime::NodeRuntime; @@ -407,7 +404,7 @@ impl Copilot { ); let http = http_client::FakeHttpClient::create(|_| async { unreachable!() }); let node_runtime = NodeRuntime::unavailable(); - let this = cx.new_model(|cx| Self { + let this = cx.new(|cx| Self { server_id: LanguageServerId(0), http: http.clone(), node_runtime, @@ -426,7 +423,7 @@ impl Copilot { new_server_id: LanguageServerId, http: Arc, node_runtime: NodeRuntime, - this: WeakModel, + this: WeakEntity, mut cx: AsyncAppContext, ) { let start_language_server = async { @@ -513,7 +510,7 @@ impl Copilot { .ok(); } - pub fn sign_in(&mut self, cx: &mut ModelContext) -> Task> { + pub fn sign_in(&mut self, cx: &mut Context) -> Task> { if let CopilotServer::Running(server) = &mut self.server { let task = match &server.sign_in_status { SignInStatus::Authorized { .. } => Task::ready(Ok(())).shared(), @@ -598,7 +595,7 @@ impl Copilot { } } - pub fn sign_out(&mut self, cx: &mut ModelContext) -> Task> { + pub fn sign_out(&mut self, cx: &mut Context) -> Task> { self.update_sign_in_status(request::SignInStatus::NotSignedIn, cx); if let CopilotServer::Running(RunningCopilotServer { lsp: server, .. }) = &self.server { let server = server.clone(); @@ -613,7 +610,7 @@ impl Copilot { } } - pub fn reinstall(&mut self, cx: &mut ModelContext) -> Task<()> { + pub fn reinstall(&mut self, cx: &mut Context) -> Task<()> { let start_task = cx .spawn({ let http = self.http.clone(); @@ -643,7 +640,7 @@ impl Copilot { } } - pub fn register_buffer(&mut self, buffer: &Model, cx: &mut ModelContext) { + pub fn register_buffer(&mut self, buffer: &Entity, cx: &mut Context) { let weak_buffer = buffer.downgrade(); self.buffers.insert(weak_buffer.clone()); @@ -699,9 +696,9 @@ impl Copilot { fn handle_buffer_event( &mut self, - buffer: Model, + buffer: Entity, event: &language::BufferEvent, - cx: &mut ModelContext, + cx: &mut Context, ) -> Result<()> { if let Ok(server) = self.server.as_running() { if let Some(registered_buffer) = server.registered_buffers.get_mut(&buffer.entity_id()) @@ -760,7 +757,7 @@ impl Copilot { Ok(()) } - fn unregister_buffer(&mut self, buffer: &WeakModel) { + fn unregister_buffer(&mut self, buffer: &WeakEntity) { if let Ok(server) = self.server.as_running() { if let Some(buffer) = server.registered_buffers.remove(&buffer.entity_id()) { server @@ -777,9 +774,9 @@ impl Copilot { pub fn completions( &mut self, - buffer: &Model, + buffer: &Entity, position: T, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task>> where T: ToPointUtf16, @@ -789,9 +786,9 @@ impl Copilot { pub fn completions_cycling( &mut self, - buffer: &Model, + buffer: &Entity, position: T, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task>> where T: ToPointUtf16, @@ -802,7 +799,7 @@ impl Copilot { pub fn accept_completion( &mut self, completion: &Completion, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { let server = match self.server.as_authenticated() { Ok(server) => server, @@ -823,7 +820,7 @@ impl Copilot { pub fn discard_completions( &mut self, completions: &[Completion], - cx: &mut ModelContext, + cx: &mut Context, ) -> Task> { let server = match self.server.as_authenticated() { Ok(server) => server, @@ -846,9 +843,9 @@ impl Copilot { fn request_completions( &mut self, - buffer: &Model, + buffer: &Entity, position: T, - cx: &mut ModelContext, + cx: &mut Context, ) -> Task>> where R: 'static @@ -937,11 +934,7 @@ impl Copilot { } } - fn update_sign_in_status( - &mut self, - lsp_status: request::SignInStatus, - cx: &mut ModelContext, - ) { + fn update_sign_in_status(&mut self, lsp_status: request::SignInStatus, cx: &mut Context) { self.buffers.retain(|buffer| buffer.is_upgradable()); if let Ok(server) = self.server.as_running() { @@ -983,7 +976,7 @@ fn id_for_language(language: Option<&Arc>) -> String { .unwrap_or_else(|| "plaintext".to_string()) } -fn uri_for_buffer(buffer: &Model, cx: &AppContext) -> lsp::Url { +fn uri_for_buffer(buffer: &Entity, cx: &App) -> lsp::Url { if let Some(file) = buffer.read(cx).file().and_then(|file| file.as_local()) { lsp::Url::from_file_path(file.abs_path(cx)).unwrap() } else { @@ -1073,7 +1066,7 @@ mod tests { async fn test_buffer_management(cx: &mut TestAppContext) { let (copilot, mut lsp) = Copilot::fake(cx); - let buffer_1 = cx.new_model(|cx| Buffer::local("Hello", cx)); + let buffer_1 = cx.new(|cx| Buffer::local("Hello", cx)); let buffer_1_uri: lsp::Url = format!("buffer://{}", buffer_1.entity_id().as_u64()) .parse() .unwrap(); @@ -1091,7 +1084,7 @@ mod tests { } ); - let buffer_2 = cx.new_model(|cx| Buffer::local("Goodbye", cx)); + let buffer_2 = cx.new(|cx| Buffer::local("Goodbye", cx)); let buffer_2_uri: lsp::Url = format!("buffer://{}", buffer_2.entity_id().as_u64()) .parse() .unwrap(); @@ -1246,11 +1239,11 @@ mod tests { &self.path } - fn full_path(&self, _: &AppContext) -> PathBuf { + fn full_path(&self, _: &App) -> PathBuf { unimplemented!() } - fn file_name<'a>(&'a self, _: &'a AppContext) -> &'a std::ffi::OsStr { + fn file_name<'a>(&'a self, _: &'a App) -> &'a std::ffi::OsStr { unimplemented!() } @@ -1258,11 +1251,11 @@ mod tests { unimplemented!() } - fn to_proto(&self, _: &AppContext) -> rpc::proto::File { + fn to_proto(&self, _: &App) -> rpc::proto::File { unimplemented!() } - fn worktree_id(&self, _: &AppContext) -> settings::WorktreeId { + fn worktree_id(&self, _: &App) -> settings::WorktreeId { settings::WorktreeId::from_usize(0) } @@ -1272,15 +1265,15 @@ mod tests { } impl language::LocalFile for File { - fn abs_path(&self, _: &AppContext) -> PathBuf { + fn abs_path(&self, _: &App) -> PathBuf { self.abs_path.clone() } - fn load(&self, _: &AppContext) -> Task> { + fn load(&self, _: &App) -> Task> { unimplemented!() } - fn load_bytes(&self, _cx: &AppContext) -> Task>> { + fn load_bytes(&self, _cx: &App) -> Task>> { unimplemented!() } } diff --git a/crates/copilot/src/copilot_chat.rs b/crates/copilot/src/copilot_chat.rs index 4391f0a955..c130ccb3cc 100644 --- a/crates/copilot/src/copilot_chat.rs +++ b/crates/copilot/src/copilot_chat.rs @@ -6,7 +6,7 @@ use anyhow::{anyhow, Result}; use chrono::DateTime; use fs::Fs; use futures::{io::BufReader, stream::BoxStream, AsyncBufReadExt, AsyncReadExt, StreamExt}; -use gpui::{prelude::*, AppContext, AsyncAppContext, Global}; +use gpui::{prelude::*, App, AsyncAppContext, Global}; use http_client::{AsyncBody, HttpClient, Method, Request as HttpRequest}; use paths::home_dir; use serde::{Deserialize, Serialize}; @@ -181,7 +181,7 @@ impl TryFrom for ApiToken { } } -struct GlobalCopilotChat(gpui::Model); +struct GlobalCopilotChat(gpui::Entity); impl Global for GlobalCopilotChat {} @@ -191,8 +191,8 @@ pub struct CopilotChat { client: Arc, } -pub fn init(fs: Arc, client: Arc, cx: &mut AppContext) { - let copilot_chat = cx.new_model(|cx| CopilotChat::new(fs, client, cx)); +pub fn init(fs: Arc, client: Arc, cx: &mut App) { + let copilot_chat = cx.new(|cx| CopilotChat::new(fs, client, cx)); cx.set_global(GlobalCopilotChat(copilot_chat)); } @@ -215,12 +215,12 @@ fn copilot_chat_config_paths() -> [PathBuf; 2] { } impl CopilotChat { - pub fn global(cx: &AppContext) -> Option> { + pub fn global(cx: &App) -> Option> { cx.try_global::() .map(|model| model.0.clone()) } - pub fn new(fs: Arc, client: Arc, cx: &AppContext) -> Self { + pub fn new(fs: Arc, client: Arc, cx: &App) -> Self { let config_paths = copilot_chat_config_paths(); let resolve_config_path = { diff --git a/crates/copilot/src/copilot_completion_provider.rs b/crates/copilot/src/copilot_completion_provider.rs index 73fc9e6a8e..0dc03e4037 100644 --- a/crates/copilot/src/copilot_completion_provider.rs +++ b/crates/copilot/src/copilot_completion_provider.rs @@ -1,6 +1,6 @@ use crate::{Completion, Copilot}; use anyhow::Result; -use gpui::{AppContext, EntityId, Model, ModelContext, Task}; +use gpui::{App, Context, Entity, EntityId, Task}; use inline_completion::{Direction, InlineCompletion, InlineCompletionProvider}; use language::{ language_settings::{all_language_settings, AllLanguageSettings}, @@ -19,11 +19,11 @@ pub struct CopilotCompletionProvider { file_extension: Option, pending_refresh: Option>>, pending_cycling_refresh: Option>>, - copilot: Model, + copilot: Entity, } impl CopilotCompletionProvider { - pub fn new(copilot: Model) -> Self { + pub fn new(copilot: Entity) -> Self { Self { cycled: false, buffer_id: None, @@ -73,9 +73,9 @@ impl InlineCompletionProvider for CopilotCompletionProvider { fn is_enabled( &self, - buffer: &Model, + buffer: &Entity, cursor_position: language::Anchor, - cx: &AppContext, + cx: &App, ) -> bool { if !self.copilot.read(cx).status().is_authorized() { return false; @@ -90,10 +90,10 @@ impl InlineCompletionProvider for CopilotCompletionProvider { fn refresh( &mut self, - buffer: Model, + buffer: Entity, cursor_position: language::Anchor, debounce: bool, - cx: &mut ModelContext, + cx: &mut Context, ) { let copilot = self.copilot.clone(); self.pending_refresh = Some(cx.spawn(|this, mut cx| async move { @@ -139,10 +139,10 @@ impl InlineCompletionProvider for CopilotCompletionProvider { fn cycle( &mut self, - buffer: Model, + buffer: Entity, cursor_position: language::Anchor, direction: Direction, - cx: &mut ModelContext, + cx: &mut Context, ) { if self.cycled { match direction { @@ -194,7 +194,7 @@ impl InlineCompletionProvider for CopilotCompletionProvider { } } - fn accept(&mut self, cx: &mut ModelContext) { + fn accept(&mut self, cx: &mut Context) { if let Some(completion) = self.active_completion() { self.copilot .update(cx, |copilot, cx| copilot.accept_completion(completion, cx)) @@ -202,7 +202,7 @@ impl InlineCompletionProvider for CopilotCompletionProvider { } } - fn discard(&mut self, cx: &mut ModelContext) { + fn discard(&mut self, cx: &mut Context) { let settings = AllLanguageSettings::get_global(cx); let copilot_enabled = settings.inline_completions_enabled(None, None, cx); @@ -220,9 +220,9 @@ impl InlineCompletionProvider for CopilotCompletionProvider { fn suggest( &mut self, - buffer: &Model, + buffer: &Entity, cursor_position: language::Anchor, - cx: &mut ModelContext, + cx: &mut Context, ) -> Option { let buffer_id = buffer.entity_id(); let buffer = buffer.read(cx); @@ -280,7 +280,7 @@ mod tests { }; use fs::FakeFs; use futures::StreamExt; - use gpui::{BackgroundExecutor, Context, TestAppContext, UpdateGlobal}; + use gpui::{AppContext as _, BackgroundExecutor, TestAppContext, UpdateGlobal}; use indoc::indoc; use language::{ language_settings::{AllLanguageSettings, AllLanguageSettingsContent}, @@ -309,9 +309,9 @@ mod tests { cx, ) .await; - let copilot_provider = cx.new_model(|_| CopilotCompletionProvider::new(copilot)); - cx.update_editor(|editor, cx| { - editor.set_inline_completion_provider(Some(copilot_provider), cx) + let copilot_provider = cx.new(|_| CopilotCompletionProvider::new(copilot)); + cx.update_editor(|editor, window, cx| { + editor.set_inline_completion_provider(Some(copilot_provider), window, cx) }); cx.set_state(indoc! {" @@ -339,7 +339,7 @@ mod tests { vec![], ); executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, window, cx| { assert!(editor.context_menu_visible()); assert!(!editor.context_menu_contains_inline_completion()); assert!(!editor.has_active_inline_completion()); @@ -350,7 +350,7 @@ mod tests { // Confirming a non-copilot completion inserts it and hides the context menu, without showing // the copilot suggestion afterwards. editor - .confirm_completion(&Default::default(), cx) + .confirm_completion(&Default::default(), window, cx) .unwrap() .detach(); assert!(!editor.context_menu_visible()); @@ -386,7 +386,7 @@ mod tests { vec![], ); executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, _, cx| { assert!(!editor.context_menu_visible()); assert!(editor.has_active_inline_completion()); // Since only the copilot is available, it's shown inline @@ -397,7 +397,7 @@ mod tests { // Ensure existing inline completion is interpolated when inserting again. cx.simulate_keystroke("c"); executor.run_until_parked(); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, _, cx| { assert!(!editor.context_menu_visible()); assert!(!editor.context_menu_contains_inline_completion()); assert!(editor.has_active_inline_completion()); @@ -416,7 +416,7 @@ mod tests { vec![], ); executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, window, cx| { assert!(!editor.context_menu_visible()); assert!(editor.has_active_inline_completion()); assert!(!editor.context_menu_contains_inline_completion()); @@ -424,19 +424,19 @@ mod tests { assert_eq!(editor.text(cx), "one.c\ntwo\nthree\n"); // Canceling should remove the active Copilot suggestion. - editor.cancel(&Default::default(), cx); + editor.cancel(&Default::default(), window, cx); assert!(!editor.has_active_inline_completion()); assert_eq!(editor.display_text(cx), "one.c\ntwo\nthree\n"); assert_eq!(editor.text(cx), "one.c\ntwo\nthree\n"); // After canceling, tabbing shouldn't insert the previously shown suggestion. - editor.tab(&Default::default(), cx); + editor.tab(&Default::default(), window, cx); assert!(!editor.has_active_inline_completion()); assert_eq!(editor.display_text(cx), "one.c \ntwo\nthree\n"); assert_eq!(editor.text(cx), "one.c \ntwo\nthree\n"); // When undoing the previously active suggestion is shown again. - editor.undo(&Default::default(), cx); + editor.undo(&Default::default(), window, cx); assert!(editor.has_active_inline_completion()); assert_eq!(editor.display_text(cx), "one.copilot2\ntwo\nthree\n"); assert_eq!(editor.text(cx), "one.c\ntwo\nthree\n"); @@ -444,25 +444,25 @@ mod tests { // If an edit occurs outside of this editor, the suggestion is still correctly interpolated. cx.update_buffer(|buffer, cx| buffer.edit([(5..5, "o")], None, cx)); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, window, cx| { assert!(editor.has_active_inline_completion()); assert_eq!(editor.display_text(cx), "one.copilot2\ntwo\nthree\n"); assert_eq!(editor.text(cx), "one.co\ntwo\nthree\n"); // AcceptInlineCompletion when there is an active suggestion inserts it. - editor.accept_inline_completion(&Default::default(), cx); + editor.accept_inline_completion(&Default::default(), window, cx); assert!(!editor.has_active_inline_completion()); assert_eq!(editor.display_text(cx), "one.copilot2\ntwo\nthree\n"); assert_eq!(editor.text(cx), "one.copilot2\ntwo\nthree\n"); // When undoing the previously active suggestion is shown again. - editor.undo(&Default::default(), cx); + editor.undo(&Default::default(), window, cx); assert!(editor.has_active_inline_completion()); assert_eq!(editor.display_text(cx), "one.copilot2\ntwo\nthree\n"); assert_eq!(editor.text(cx), "one.co\ntwo\nthree\n"); // Hide suggestion. - editor.cancel(&Default::default(), cx); + editor.cancel(&Default::default(), window, cx); assert!(!editor.has_active_inline_completion()); assert_eq!(editor.display_text(cx), "one.co\ntwo\nthree\n"); assert_eq!(editor.text(cx), "one.co\ntwo\nthree\n"); @@ -471,16 +471,16 @@ mod tests { // If an edit occurs outside of this editor but no suggestion is being shown, // we won't make it visible. cx.update_buffer(|buffer, cx| buffer.edit([(6..6, "p")], None, cx)); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, _, cx| { assert!(!editor.has_active_inline_completion()); assert_eq!(editor.display_text(cx), "one.cop\ntwo\nthree\n"); assert_eq!(editor.text(cx), "one.cop\ntwo\nthree\n"); }); // Reset the editor to verify how suggestions behave when tabbing on leading indentation. - cx.update_editor(|editor, cx| { - editor.set_text("fn foo() {\n \n}", cx); - editor.change_selections(None, cx, |s| { + cx.update_editor(|editor, window, cx| { + editor.set_text("fn foo() {\n \n}", window, cx); + editor.change_selections(None, window, cx, |s| { s.select_ranges([Point::new(1, 2)..Point::new(1, 2)]) }); }); @@ -494,21 +494,23 @@ mod tests { vec![], ); - cx.update_editor(|editor, cx| editor.next_inline_completion(&Default::default(), cx)); + cx.update_editor(|editor, window, cx| { + editor.next_inline_completion(&Default::default(), window, cx) + }); executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, window, cx| { assert!(editor.has_active_inline_completion()); assert_eq!(editor.display_text(cx), "fn foo() {\n let x = 4;\n}"); assert_eq!(editor.text(cx), "fn foo() {\n \n}"); // Tabbing inside of leading whitespace inserts indentation without accepting the suggestion. - editor.tab(&Default::default(), cx); + editor.tab(&Default::default(), window, cx); assert!(editor.has_active_inline_completion()); assert_eq!(editor.text(cx), "fn foo() {\n \n}"); assert_eq!(editor.display_text(cx), "fn foo() {\n let x = 4;\n}"); // Using AcceptInlineCompletion again accepts the suggestion. - editor.accept_inline_completion(&Default::default(), cx); + editor.accept_inline_completion(&Default::default(), window, cx); assert!(!editor.has_active_inline_completion()); assert_eq!(editor.text(cx), "fn foo() {\n let x = 4;\n}"); assert_eq!(editor.display_text(cx), "fn foo() {\n let x = 4;\n}"); @@ -535,9 +537,9 @@ mod tests { cx, ) .await; - let copilot_provider = cx.new_model(|_| CopilotCompletionProvider::new(copilot)); - cx.update_editor(|editor, cx| { - editor.set_inline_completion_provider(Some(copilot_provider), cx) + let copilot_provider = cx.new(|_| CopilotCompletionProvider::new(copilot)); + cx.update_editor(|editor, window, cx| { + editor.set_inline_completion_provider(Some(copilot_provider), window, cx) }); // Setup the editor with a completion request. @@ -566,17 +568,17 @@ mod tests { vec![], ); executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, window, cx| { assert!(editor.has_active_inline_completion()); // Accepting the first word of the suggestion should only accept the first word and still show the rest. - editor.accept_partial_inline_completion(&Default::default(), cx); + editor.accept_partial_inline_completion(&Default::default(), window, cx); assert!(editor.has_active_inline_completion()); assert_eq!(editor.text(cx), "one.copilot\ntwo\nthree\n"); assert_eq!(editor.display_text(cx), "one.copilot1\ntwo\nthree\n"); // Accepting next word should accept the non-word and copilot suggestion should be gone - editor.accept_partial_inline_completion(&Default::default(), cx); + editor.accept_partial_inline_completion(&Default::default(), window, cx); assert!(!editor.has_active_inline_completion()); assert_eq!(editor.text(cx), "one.copilot1\ntwo\nthree\n"); assert_eq!(editor.display_text(cx), "one.copilot1\ntwo\nthree\n"); @@ -608,11 +610,11 @@ mod tests { vec![], ); executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, window, cx| { assert!(editor.has_active_inline_completion()); // Accepting the first word (non-word) of the suggestion should only accept the first word and still show the rest. - editor.accept_partial_inline_completion(&Default::default(), cx); + editor.accept_partial_inline_completion(&Default::default(), window, cx); assert!(editor.has_active_inline_completion()); assert_eq!(editor.text(cx), "one.123. \ntwo\nthree\n"); assert_eq!( @@ -621,7 +623,7 @@ mod tests { ); // Accepting next word should accept the next word and copilot suggestion should still exist - editor.accept_partial_inline_completion(&Default::default(), cx); + editor.accept_partial_inline_completion(&Default::default(), window, cx); assert!(editor.has_active_inline_completion()); assert_eq!(editor.text(cx), "one.123. copilot\ntwo\nthree\n"); assert_eq!( @@ -630,7 +632,7 @@ mod tests { ); // Accepting the whitespace should accept the non-word/whitespaces with newline and copilot suggestion should be gone - editor.accept_partial_inline_completion(&Default::default(), cx); + editor.accept_partial_inline_completion(&Default::default(), window, cx); assert!(!editor.has_active_inline_completion()); assert_eq!(editor.text(cx), "one.123. copilot\n 456\ntwo\nthree\n"); assert_eq!( @@ -659,9 +661,9 @@ mod tests { cx, ) .await; - let copilot_provider = cx.new_model(|_| CopilotCompletionProvider::new(copilot)); - cx.update_editor(|editor, cx| { - editor.set_inline_completion_provider(Some(copilot_provider), cx) + let copilot_provider = cx.new(|_| CopilotCompletionProvider::new(copilot)); + cx.update_editor(|editor, window, cx| { + editor.set_inline_completion_provider(Some(copilot_provider), window, cx) }); cx.set_state(indoc! {" @@ -679,31 +681,33 @@ mod tests { }], vec![], ); - cx.update_editor(|editor, cx| editor.next_inline_completion(&Default::default(), cx)); + cx.update_editor(|editor, window, cx| { + editor.next_inline_completion(&Default::default(), window, cx) + }); executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, window, cx| { assert!(editor.has_active_inline_completion()); assert_eq!(editor.display_text(cx), "one\ntwo.foo()\nthree\n"); assert_eq!(editor.text(cx), "one\ntw\nthree\n"); - editor.backspace(&Default::default(), cx); + editor.backspace(&Default::default(), window, cx); assert!(editor.has_active_inline_completion()); assert_eq!(editor.display_text(cx), "one\ntwo.foo()\nthree\n"); assert_eq!(editor.text(cx), "one\nt\nthree\n"); - editor.backspace(&Default::default(), cx); + editor.backspace(&Default::default(), window, cx); assert!(editor.has_active_inline_completion()); assert_eq!(editor.display_text(cx), "one\ntwo.foo()\nthree\n"); assert_eq!(editor.text(cx), "one\n\nthree\n"); // Deleting across the original suggestion range invalidates it. - editor.backspace(&Default::default(), cx); + editor.backspace(&Default::default(), window, cx); assert!(!editor.has_active_inline_completion()); assert_eq!(editor.display_text(cx), "one\nthree\n"); assert_eq!(editor.text(cx), "one\nthree\n"); // Undoing the deletion restores the suggestion. - editor.undo(&Default::default(), cx); + editor.undo(&Default::default(), window, cx); assert!(editor.has_active_inline_completion()); assert_eq!(editor.display_text(cx), "one\ntwo.foo()\nthree\n"); assert_eq!(editor.text(cx), "one\n\nthree\n"); @@ -716,9 +720,9 @@ mod tests { let (copilot, copilot_lsp) = Copilot::fake(cx); - let buffer_1 = cx.new_model(|cx| Buffer::local("a = 1\nb = 2\n", cx)); - let buffer_2 = cx.new_model(|cx| Buffer::local("c = 3\nd = 4\n", cx)); - let multibuffer = cx.new_model(|cx| { + let buffer_1 = cx.new(|cx| Buffer::local("a = 1\nb = 2\n", cx)); + let buffer_2 = cx.new(|cx| Buffer::local("c = 3\nd = 4\n", cx)); + let multibuffer = cx.new(|cx| { let mut multibuffer = MultiBuffer::new(language::Capability::ReadWrite); multibuffer.push_excerpts( buffer_1.clone(), @@ -738,12 +742,18 @@ mod tests { ); multibuffer }); - let editor = cx.add_window(|cx| Editor::for_multibuffer(multibuffer, None, true, cx)); - editor.update(cx, |editor, cx| editor.focus(cx)).unwrap(); - let copilot_provider = cx.new_model(|_| CopilotCompletionProvider::new(copilot)); + let editor = cx + .add_window(|window, cx| Editor::for_multibuffer(multibuffer, None, true, window, cx)); editor - .update(cx, |editor, cx| { - editor.set_inline_completion_provider(Some(copilot_provider), cx) + .update(cx, |editor, window, cx| { + use gpui::Focusable; + window.focus(&editor.focus_handle(cx)); + }) + .unwrap(); + let copilot_provider = cx.new(|_| CopilotCompletionProvider::new(copilot)); + editor + .update(cx, |editor, window, cx| { + editor.set_inline_completion_provider(Some(copilot_provider), window, cx) }) .unwrap(); @@ -756,15 +766,15 @@ mod tests { }], vec![], ); - _ = editor.update(cx, |editor, cx| { + _ = editor.update(cx, |editor, window, cx| { // Ensure copilot suggestions are shown for the first excerpt. - editor.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select_ranges([Point::new(1, 5)..Point::new(1, 5)]) }); - editor.next_inline_completion(&Default::default(), cx); + editor.next_inline_completion(&Default::default(), window, cx); }); executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); - _ = editor.update(cx, |editor, cx| { + _ = editor.update(cx, |editor, _, cx| { assert!(editor.has_active_inline_completion()); assert_eq!( editor.display_text(cx), @@ -782,9 +792,9 @@ mod tests { }], vec![], ); - _ = editor.update(cx, |editor, cx| { + _ = editor.update(cx, |editor, window, cx| { // Move to another excerpt, ensuring the suggestion gets cleared. - editor.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select_ranges([Point::new(4, 5)..Point::new(4, 5)]) }); assert!(!editor.has_active_inline_completion()); @@ -795,7 +805,7 @@ mod tests { assert_eq!(editor.text(cx), "a = 1\nb = 2\n\nc = 3\nd = 4\n"); // Type a character, ensuring we don't even try to interpolate the previous suggestion. - editor.handle_input(" ", cx); + editor.handle_input(" ", window, cx); assert!(!editor.has_active_inline_completion()); assert_eq!( editor.display_text(cx), @@ -806,7 +816,7 @@ mod tests { // Ensure the new suggestion is displayed when the debounce timeout expires. executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); - _ = editor.update(cx, |editor, cx| { + _ = editor.update(cx, |editor, _, cx| { assert!(editor.has_active_inline_completion()); assert_eq!( editor.display_text(cx), @@ -835,9 +845,9 @@ mod tests { cx, ) .await; - let copilot_provider = cx.new_model(|_| CopilotCompletionProvider::new(copilot)); - cx.update_editor(|editor, cx| { - editor.set_inline_completion_provider(Some(copilot_provider), cx) + let copilot_provider = cx.new(|_| CopilotCompletionProvider::new(copilot)); + cx.update_editor(|editor, window, cx| { + editor.set_inline_completion_provider(Some(copilot_provider), window, cx) }); cx.set_state(indoc! {" @@ -864,9 +874,11 @@ mod tests { }], vec![], ); - cx.update_editor(|editor, cx| editor.next_inline_completion(&Default::default(), cx)); + cx.update_editor(|editor, window, cx| { + editor.next_inline_completion(&Default::default(), window, cx) + }); executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, _, cx| { assert!(!editor.context_menu_visible()); assert!(editor.has_active_inline_completion()); assert_eq!(editor.display_text(cx), "one\ntwo.foo()\nthree\n"); @@ -893,7 +905,7 @@ mod tests { vec![], ); executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, _, cx| { assert!(!editor.context_menu_visible()); assert!(editor.has_active_inline_completion()); assert_eq!(editor.display_text(cx), "one\ntwo.foo()\nthree\n"); @@ -920,7 +932,7 @@ mod tests { vec![], ); executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, _, cx| { assert!(editor.context_menu_visible()); assert!(!editor.context_menu_contains_inline_completion()); assert!(!editor.has_active_inline_completion(),); @@ -963,7 +975,7 @@ mod tests { .await .unwrap(); - let multibuffer = cx.new_model(|cx| { + let multibuffer = cx.new(|cx| { let mut multibuffer = MultiBuffer::new(language::Capability::ReadWrite); multibuffer.push_excerpts( private_buffer.clone(), @@ -983,12 +995,18 @@ mod tests { ); multibuffer }); - let editor = cx.add_window(|cx| Editor::for_multibuffer(multibuffer, None, true, cx)); - editor.update(cx, |editor, cx| editor.focus(cx)).unwrap(); - let copilot_provider = cx.new_model(|_| CopilotCompletionProvider::new(copilot)); + let editor = cx + .add_window(|window, cx| Editor::for_multibuffer(multibuffer, None, true, window, cx)); editor - .update(cx, |editor, cx| { - editor.set_inline_completion_provider(Some(copilot_provider), cx) + .update(cx, |editor, window, cx| { + use gpui::Focusable; + window.focus(&editor.focus_handle(cx)) + }) + .unwrap(); + let copilot_provider = cx.new(|_| CopilotCompletionProvider::new(copilot)); + editor + .update(cx, |editor, window, cx| { + editor.set_inline_completion_provider(Some(copilot_provider), window, cx) }) .unwrap(); @@ -1008,21 +1026,21 @@ mod tests { }, ); - _ = editor.update(cx, |editor, cx| { - editor.change_selections(None, cx, |selections| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |selections| { selections.select_ranges([Point::new(0, 0)..Point::new(0, 0)]) }); - editor.refresh_inline_completion(true, false, cx); + editor.refresh_inline_completion(true, false, window, cx); }); executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); assert!(copilot_requests.try_next().is_err()); - _ = editor.update(cx, |editor, cx| { - editor.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_ranges([Point::new(5, 0)..Point::new(5, 0)]) }); - editor.refresh_inline_completion(true, false, cx); + editor.refresh_inline_completion(true, false, window, cx); }); executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); diff --git a/crates/copilot/src/sign_in.rs b/crates/copilot/src/sign_in.rs index 68f0eed577..5d79f00a77 100644 --- a/crates/copilot/src/sign_in.rs +++ b/crates/copilot/src/sign_in.rs @@ -1,8 +1,8 @@ use crate::{request::PromptUserDeviceFlow, Copilot, Status}; use gpui::{ - div, AppContext, ClipboardItem, DismissEvent, Element, EventEmitter, FocusHandle, - FocusableView, InteractiveElement, IntoElement, Model, MouseDownEvent, ParentElement, Render, - Styled, Subscription, ViewContext, + div, App, ClipboardItem, Context, DismissEvent, Element, Entity, EventEmitter, FocusHandle, + Focusable, InteractiveElement, IntoElement, MouseDownEvent, ParentElement, Render, Styled, + Subscription, Window, }; use ui::{prelude::*, Button, Label, Vector, VectorName}; use util::ResultExt as _; @@ -13,21 +13,21 @@ const COPILOT_SIGN_UP_URL: &str = "https://github.com/features/copilot"; struct CopilotStartingToast; -pub fn initiate_sign_in(cx: &mut WindowContext) { +pub fn initiate_sign_in(window: &mut Window, cx: &mut App) { let Some(copilot) = Copilot::global(cx) else { return; }; let status = copilot.read(cx).status(); - let Some(workspace) = cx.window_handle().downcast::() else { + let Some(workspace) = window.window_handle().downcast::() else { return; }; match status { Status::Starting { task } => { - let Some(workspace) = cx.window_handle().downcast::() else { + let Some(workspace) = window.window_handle().downcast::() else { return; }; - let Ok(workspace) = workspace.update(cx, |workspace, cx| { + let Ok(workspace) = workspace.update(cx, |workspace, _window, cx| { workspace.show_toast( Toast::new( NotificationId::unique::(), @@ -70,8 +70,10 @@ pub fn initiate_sign_in(cx: &mut WindowContext) { _ => { copilot.update(cx, |this, cx| this.sign_in(cx)).detach(); workspace - .update(cx, |this, cx| { - this.toggle_modal(cx, |cx| CopilotCodeVerification::new(&copilot, cx)); + .update(cx, |this, window, cx| { + this.toggle_modal(window, cx, |_, cx| { + CopilotCodeVerification::new(&copilot, cx) + }); }) .ok(); } @@ -85,8 +87,8 @@ pub struct CopilotCodeVerification { _subscription: Subscription, } -impl FocusableView for CopilotCodeVerification { - fn focus_handle(&self, _: &AppContext) -> gpui::FocusHandle { +impl Focusable for CopilotCodeVerification { + fn focus_handle(&self, _: &App) -> gpui::FocusHandle { self.focus_handle.clone() } } @@ -95,7 +97,7 @@ impl EventEmitter for CopilotCodeVerification {} impl ModalView for CopilotCodeVerification {} impl CopilotCodeVerification { - pub fn new(copilot: &Model, cx: &mut ViewContext) -> Self { + pub fn new(copilot: &Entity, cx: &mut Context) -> Self { let status = copilot.read(cx).status(); Self { status, @@ -113,15 +115,12 @@ impl CopilotCodeVerification { } } - pub fn set_status(&mut self, status: Status, cx: &mut ViewContext) { + pub fn set_status(&mut self, status: Status, cx: &mut Context) { self.status = status; cx.notify(); } - fn render_device_code( - data: &PromptUserDeviceFlow, - cx: &mut ViewContext, - ) -> impl IntoElement { + fn render_device_code(data: &PromptUserDeviceFlow, cx: &mut Context) -> impl IntoElement { let copied = cx .read_from_clipboard() .map(|item| item.text().as_ref() == Some(&data.user_code)) @@ -136,9 +135,9 @@ impl CopilotCodeVerification { .justify_between() .on_mouse_down(gpui::MouseButton::Left, { let user_code = data.user_code.clone(); - move |_, cx| { + move |_, window, cx| { cx.write_to_clipboard(ClipboardItem::new_string(user_code.clone())); - cx.refresh(); + window.refresh(); } }) .child(div().flex_1().child(Label::new(data.user_code.clone()))) @@ -152,7 +151,8 @@ impl CopilotCodeVerification { fn render_prompting_modal( connect_clicked: bool, data: &PromptUserDeviceFlow, - cx: &mut ViewContext, + + cx: &mut Context, ) -> impl Element { let connect_button_label = if connect_clicked { "Waiting for connection..." @@ -177,7 +177,7 @@ impl CopilotCodeVerification { Button::new("connect-button", connect_button_label) .on_click({ let verification_uri = data.verification_uri.clone(); - cx.listener(move |this, _, cx| { + cx.listener(move |this, _, _window, cx| { cx.open_url(&verification_uri); this.connect_clicked = true; }) @@ -188,10 +188,10 @@ impl CopilotCodeVerification { .child( Button::new("copilot-enable-cancel-button", "Cancel") .full_width() - .on_click(cx.listener(|_, _, cx| cx.emit(DismissEvent))), + .on_click(cx.listener(|_, _, _, cx| cx.emit(DismissEvent))), ) } - fn render_enabled_modal(cx: &mut ViewContext) -> impl Element { + fn render_enabled_modal(cx: &mut Context) -> impl Element { v_flex() .gap_2() .child(Headline::new("Copilot Enabled!").size(HeadlineSize::Large)) @@ -201,11 +201,11 @@ impl CopilotCodeVerification { .child( Button::new("copilot-enabled-done-button", "Done") .full_width() - .on_click(cx.listener(|_, _, cx| cx.emit(DismissEvent))), + .on_click(cx.listener(|_, _, _, cx| cx.emit(DismissEvent))), ) } - fn render_unauthorized_modal(cx: &mut ViewContext) -> impl Element { + fn render_unauthorized_modal(cx: &mut Context) -> impl Element { v_flex() .child(Headline::new("You must have an active GitHub Copilot subscription.").size(HeadlineSize::Large)) @@ -215,12 +215,12 @@ impl CopilotCodeVerification { .child( Button::new("copilot-subscribe-button", "Subscribe on GitHub") .full_width() - .on_click(|_, cx| cx.open_url(COPILOT_SIGN_UP_URL)), + .on_click(|_, _, cx| cx.open_url(COPILOT_SIGN_UP_URL)), ) .child( Button::new("copilot-subscribe-cancel-button", "Cancel") .full_width() - .on_click(cx.listener(|_, _, cx| cx.emit(DismissEvent))), + .on_click(cx.listener(|_, _, _, cx| cx.emit(DismissEvent))), ) } @@ -232,7 +232,7 @@ impl CopilotCodeVerification { } impl Render for CopilotCodeVerification { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { let prompt = match &self.status { Status::SigningIn { prompt: Some(prompt), @@ -260,11 +260,11 @@ impl Render for CopilotCodeVerification { .items_center() .p_4() .gap_2() - .on_action(cx.listener(|_, _: &menu::Cancel, cx| { + .on_action(cx.listener(|_, _: &menu::Cancel, _, cx| { cx.emit(DismissEvent); })) - .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, cx| { - cx.focus(&this.focus_handle); + .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, _| { + window.focus(&this.focus_handle); })) .child( Vector::new(VectorName::ZedXCopilot, rems(8.), rems(4.)) diff --git a/crates/db/src/db.rs b/crates/db/src/db.rs index 98fca60d63..b825855dbe 100644 --- a/crates/db/src/db.rs +++ b/crates/db/src/db.rs @@ -3,8 +3,8 @@ pub mod query; // Re-export pub use anyhow; -use anyhow::Context; -use gpui::AppContext; +use anyhow::Context as _; +use gpui::App; pub use indoc::indoc; pub use paths::database_dir; pub use smol; @@ -188,7 +188,7 @@ macro_rules! define_connection { }; } -pub fn write_and_log(cx: &AppContext, db_write: impl FnOnce() -> F + Send + 'static) +pub fn write_and_log(cx: &App, db_write: impl FnOnce() -> F + Send + 'static) where F: Future> + Send, { diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 71f96e9f9b..04dfaa7a89 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -15,10 +15,9 @@ use editor::{ Editor, EditorEvent, ExcerptId, ExcerptRange, MultiBuffer, ToOffset, }; use gpui::{ - actions, div, svg, AnyElement, AnyView, AppContext, Context, EventEmitter, FocusHandle, - FocusableView, Global, HighlightStyle, InteractiveElement, IntoElement, Model, ParentElement, - Render, SharedString, Styled, StyledText, Subscription, Task, View, ViewContext, VisualContext, - WeakView, WindowContext, + actions, div, svg, AnyElement, AnyView, App, Context, Entity, EventEmitter, FocusHandle, + Focusable, Global, HighlightStyle, InteractiveElement, IntoElement, ParentElement, Render, + SharedString, Styled, StyledText, Subscription, Task, WeakEntity, Window, }; use language::{ Bias, Buffer, BufferRow, BufferSnapshot, Diagnostic, DiagnosticEntry, DiagnosticSeverity, @@ -52,19 +51,18 @@ actions!(diagnostics, [Deploy, ToggleWarnings]); struct IncludeWarnings(bool); impl Global for IncludeWarnings {} -pub fn init(cx: &mut AppContext) { +pub fn init(cx: &mut App) { ProjectDiagnosticsSettings::register(cx); - cx.observe_new_views(ProjectDiagnosticsEditor::register) - .detach(); + cx.observe_new(ProjectDiagnosticsEditor::register).detach(); } struct ProjectDiagnosticsEditor { - project: Model, - workspace: WeakView, + project: Entity, + workspace: WeakEntity, focus_handle: FocusHandle, - editor: View, + editor: Entity, summary: DiagnosticSummary, - excerpts: Model, + excerpts: Entity, path_states: Vec, paths_to_update: BTreeSet<(ProjectPath, Option)>, include_warnings: bool, @@ -92,7 +90,7 @@ impl EventEmitter for ProjectDiagnosticsEditor {} const DIAGNOSTICS_UPDATE_DEBOUNCE: Duration = Duration::from_millis(50); impl Render for ProjectDiagnosticsEditor { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { let child = if self.path_states.is_empty() { div() .key_context("EmptyPane") @@ -116,25 +114,30 @@ impl Render for ProjectDiagnosticsEditor { } impl ProjectDiagnosticsEditor { - fn register(workspace: &mut Workspace, _: &mut ViewContext) { + fn register( + workspace: &mut Workspace, + _window: Option<&mut Window>, + _: &mut Context, + ) { workspace.register_action(Self::deploy); } fn new_with_context( context: u32, include_warnings: bool, - project_handle: Model, - workspace: WeakView, - cx: &mut ViewContext, + project_handle: Entity, + workspace: WeakEntity, + window: &mut Window, + cx: &mut Context, ) -> Self { let project_event_subscription = - cx.subscribe(&project_handle, |this, project, event, cx| match event { + cx.subscribe_in(&project_handle, window, |this, project, event, window, cx| match event { project::Event::DiskBasedDiagnosticsStarted { .. } => { cx.notify(); } project::Event::DiskBasedDiagnosticsFinished { language_server_id } => { log::debug!("disk based diagnostics finished for server {language_server_id}"); - this.update_stale_excerpts(cx); + this.update_stale_excerpts(window, cx); } project::Event::DiagnosticsUpdated { language_server_id, @@ -145,45 +148,58 @@ impl ProjectDiagnosticsEditor { this.summary = project.read(cx).diagnostic_summary(false, cx); cx.emit(EditorEvent::TitleChanged); - if this.editor.focus_handle(cx).contains_focused(cx) || this.focus_handle.contains_focused(cx) { + if this.editor.focus_handle(cx).contains_focused(window, cx) || this.focus_handle.contains_focused(window, cx) { log::debug!("diagnostics updated for server {language_server_id}, path {path:?}. recording change"); } else { log::debug!("diagnostics updated for server {language_server_id}, path {path:?}. updating excerpts"); - this.update_stale_excerpts(cx); + this.update_stale_excerpts(window, cx); } } _ => {} }); let focus_handle = cx.focus_handle(); - cx.on_focus_in(&focus_handle, |this, cx| this.focus_in(cx)) - .detach(); - cx.on_focus_out(&focus_handle, |this, _event, cx| this.focus_out(cx)) - .detach(); + cx.on_focus_in(&focus_handle, window, |this, window, cx| { + this.focus_in(window, cx) + }) + .detach(); + cx.on_focus_out(&focus_handle, window, |this, _event, window, cx| { + this.focus_out(window, cx) + }) + .detach(); - let excerpts = cx.new_model(|cx| MultiBuffer::new(project_handle.read(cx).capability())); - let editor = cx.new_view(|cx| { - let mut editor = - Editor::for_multibuffer(excerpts.clone(), Some(project_handle.clone()), true, cx); + let excerpts = cx.new(|cx| MultiBuffer::new(project_handle.read(cx).capability())); + let editor = cx.new(|cx| { + let mut editor = Editor::for_multibuffer( + excerpts.clone(), + Some(project_handle.clone()), + true, + window, + cx, + ); editor.set_vertical_scroll_margin(5, cx); editor }); - cx.subscribe(&editor, |this, _editor, event: &EditorEvent, cx| { - cx.emit(event.clone()); - match event { - EditorEvent::Focused => { - if this.path_states.is_empty() { - cx.focus(&this.focus_handle); + cx.subscribe_in( + &editor, + window, + |this, _editor, event: &EditorEvent, window, cx| { + cx.emit(event.clone()); + match event { + EditorEvent::Focused => { + if this.path_states.is_empty() { + window.focus(&this.focus_handle); + } } + EditorEvent::Blurred => this.update_stale_excerpts(window, cx), + _ => {} } - EditorEvent::Blurred => this.update_stale_excerpts(cx), - _ => {} - } - }) + }, + ) .detach(); - cx.observe_global::(|this, cx| { + cx.observe_global_in::(window, |this, window, cx| { this.include_warnings = cx.global::().0; - this.update_all_excerpts(cx); + this.update_all_excerpts(window, cx); }) .detach(); @@ -202,16 +218,16 @@ impl ProjectDiagnosticsEditor { update_excerpts_task: None, _subscription: project_event_subscription, }; - this.update_all_excerpts(cx); + this.update_all_excerpts(window, cx); this } - fn update_stale_excerpts(&mut self, cx: &mut ViewContext) { + fn update_stale_excerpts(&mut self, window: &mut Window, cx: &mut Context) { if self.update_excerpts_task.is_some() { return; } let project_handle = self.project.clone(); - self.update_excerpts_task = Some(cx.spawn(|this, mut cx| async move { + self.update_excerpts_task = Some(cx.spawn_in(window, |this, mut cx| async move { cx.background_executor() .timer(DIAGNOSTICS_UPDATE_DEBOUNCE) .await; @@ -232,8 +248,8 @@ impl ProjectDiagnosticsEditor { .await .log_err() { - this.update(&mut cx, |this, cx| { - this.update_excerpts(path, language_server_id, buffer, cx); + this.update_in(&mut cx, |this, window, cx| { + this.update_excerpts(path, language_server_id, buffer, window, cx); })?; } } @@ -242,65 +258,74 @@ impl ProjectDiagnosticsEditor { } fn new( - project_handle: Model, + project_handle: Entity, include_warnings: bool, - workspace: WeakView, - cx: &mut ViewContext, + workspace: WeakEntity, + window: &mut Window, + cx: &mut Context, ) -> Self { Self::new_with_context( editor::DEFAULT_MULTIBUFFER_CONTEXT, include_warnings, project_handle, workspace, + window, cx, ) } - fn deploy(workspace: &mut Workspace, _: &Deploy, cx: &mut ViewContext) { + fn deploy( + workspace: &mut Workspace, + _: &Deploy, + window: &mut Window, + cx: &mut Context, + ) { if let Some(existing) = workspace.item_of_type::(cx) { - workspace.activate_item(&existing, true, true, cx); + workspace.activate_item(&existing, true, true, window, cx); } else { - let workspace_handle = cx.view().downgrade(); + let workspace_handle = cx.model().downgrade(); let include_warnings = match cx.try_global::() { Some(include_warnings) => include_warnings.0, None => ProjectDiagnosticsSettings::get_global(cx).include_warnings, }; - let diagnostics = cx.new_view(|cx| { + let diagnostics = cx.new(|cx| { ProjectDiagnosticsEditor::new( workspace.project().clone(), include_warnings, workspace_handle, + window, cx, ) }); - workspace.add_item_to_active_pane(Box::new(diagnostics), None, true, cx); + workspace.add_item_to_active_pane(Box::new(diagnostics), None, true, window, cx); } } - fn toggle_warnings(&mut self, _: &ToggleWarnings, cx: &mut ViewContext) { + fn toggle_warnings(&mut self, _: &ToggleWarnings, window: &mut Window, cx: &mut Context) { self.include_warnings = !self.include_warnings; cx.set_global(IncludeWarnings(self.include_warnings)); - self.update_all_excerpts(cx); + self.update_all_excerpts(window, cx); cx.notify(); } - fn focus_in(&mut self, cx: &mut ViewContext) { - if self.focus_handle.is_focused(cx) && !self.path_states.is_empty() { - self.editor.focus_handle(cx).focus(cx) + fn focus_in(&mut self, window: &mut Window, cx: &mut Context) { + if self.focus_handle.is_focused(window) && !self.path_states.is_empty() { + self.editor.focus_handle(cx).focus(window) } } - fn focus_out(&mut self, cx: &mut ViewContext) { - if !self.focus_handle.is_focused(cx) && !self.editor.focus_handle(cx).is_focused(cx) { - self.update_stale_excerpts(cx); + fn focus_out(&mut self, window: &mut Window, cx: &mut Context) { + if !self.focus_handle.is_focused(window) && !self.editor.focus_handle(cx).is_focused(window) + { + self.update_stale_excerpts(window, cx); } } /// Enqueue an update of all excerpts. Updates all paths that either /// currently have diagnostics or are currently present in this view. - fn update_all_excerpts(&mut self, cx: &mut ViewContext) { + fn update_all_excerpts(&mut self, window: &mut Window, cx: &mut Context) { self.project.update(cx, |project, cx| { let mut paths = project .diagnostic_summaries(false, cx) @@ -315,15 +340,16 @@ impl ProjectDiagnosticsEditor { paths.extend(paths_to_update.into_iter().map(|(path, _)| (path, None))); self.paths_to_update = paths; }); - self.update_stale_excerpts(cx); + self.update_stale_excerpts(window, cx); } fn update_excerpts( &mut self, path_to_update: ProjectPath, server_to_update: Option, - buffer: Model, - cx: &mut ViewContext, + buffer: Entity, + window: &mut Window, + cx: &mut Context, ) { let was_empty = self.path_states.is_empty(); let snapshot = buffer.read(cx).snapshot(); @@ -579,12 +605,12 @@ impl ProjectDiagnosticsEditor { } else { groups = self.path_states.get(path_ix)?.diagnostic_groups.as_slice(); new_excerpt_ids_by_selection_id = - editor.change_selections(Some(Autoscroll::fit()), cx, |s| s.refresh()); + editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.refresh()); selections = editor.selections.all::(cx); } // If any selection has lost its position, move it to start of the next primary diagnostic. - let snapshot = editor.snapshot(cx); + let snapshot = editor.snapshot(window, cx); for selection in &mut selections { if let Some(new_excerpt_id) = new_excerpt_ids_by_selection_id.get(&selection.id) { let group_ix = match groups.binary_search_by(|probe| { @@ -610,19 +636,19 @@ impl ProjectDiagnosticsEditor { } } } - editor.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select(selections); }); Some(()) }); if self.path_states.is_empty() { - if self.editor.focus_handle(cx).is_focused(cx) { - cx.focus(&self.focus_handle); + if self.editor.focus_handle(cx).is_focused(window) { + window.focus(&self.focus_handle); } - } else if self.focus_handle.is_focused(cx) { + } else if self.focus_handle.is_focused(window) { let focus_handle = self.editor.focus_handle(cx); - cx.focus(&focus_handle); + window.focus(&focus_handle); } #[cfg(test)] @@ -632,7 +658,7 @@ impl ProjectDiagnosticsEditor { } #[cfg(test)] - fn check_invariants(&self, cx: &mut ViewContext) { + fn check_invariants(&self, cx: &mut Context) { let mut excerpts = Vec::new(); for (id, buffer, _) in self.excerpts.read(cx).snapshot(cx).excerpts() { if let Some(file) = buffer.file() { @@ -652,8 +678,8 @@ impl ProjectDiagnosticsEditor { } } -impl FocusableView for ProjectDiagnosticsEditor { - fn focus_handle(&self, _: &AppContext) -> FocusHandle { +impl Focusable for ProjectDiagnosticsEditor { + fn focus_handle(&self, _: &App) -> FocusHandle { self.focus_handle.clone() } } @@ -665,20 +691,26 @@ impl Item for ProjectDiagnosticsEditor { Editor::to_item_events(event, f) } - fn deactivated(&mut self, cx: &mut ViewContext) { - self.editor.update(cx, |editor, cx| editor.deactivated(cx)); - } - - fn navigate(&mut self, data: Box, cx: &mut ViewContext) -> bool { + fn deactivated(&mut self, window: &mut Window, cx: &mut Context) { self.editor - .update(cx, |editor, cx| editor.navigate(data, cx)) + .update(cx, |editor, cx| editor.deactivated(window, cx)); } - fn tab_tooltip_text(&self, _: &AppContext) -> Option { + fn navigate( + &mut self, + data: Box, + window: &mut Window, + cx: &mut Context, + ) -> bool { + self.editor + .update(cx, |editor, cx| editor.navigate(data, window, cx)) + } + + fn tab_tooltip_text(&self, _: &App) -> Option { Some("Project Diagnostics".into()) } - fn tab_content(&self, params: TabContentParams, _: &WindowContext) -> AnyElement { + fn tab_content(&self, params: TabContentParams, _window: &Window, _: &App) -> AnyElement { h_flex() .gap_1() .when( @@ -723,17 +755,22 @@ impl Item for ProjectDiagnosticsEditor { fn for_each_project_item( &self, - cx: &AppContext, + cx: &App, f: &mut dyn FnMut(gpui::EntityId, &dyn project::ProjectItem), ) { self.editor.for_each_project_item(cx, f) } - fn is_singleton(&self, _: &AppContext) -> bool { + fn is_singleton(&self, _: &App) -> bool { false } - fn set_nav_history(&mut self, nav_history: ItemNavHistory, cx: &mut ViewContext) { + fn set_nav_history( + &mut self, + nav_history: ItemNavHistory, + _: &mut Window, + cx: &mut Context, + ) { self.editor.update(cx, |editor, _| { editor.set_nav_history(Some(nav_history)); }); @@ -742,64 +779,73 @@ impl Item for ProjectDiagnosticsEditor { fn clone_on_split( &self, _workspace_id: Option, - cx: &mut ViewContext, - ) -> Option> + window: &mut Window, + cx: &mut Context, + ) -> Option> where Self: Sized, { - Some(cx.new_view(|cx| { + Some(cx.new(|cx| { ProjectDiagnosticsEditor::new( self.project.clone(), self.include_warnings, self.workspace.clone(), + window, cx, ) })) } - fn is_dirty(&self, cx: &AppContext) -> bool { + fn is_dirty(&self, cx: &App) -> bool { self.excerpts.read(cx).is_dirty(cx) } - fn has_deleted_file(&self, cx: &AppContext) -> bool { + fn has_deleted_file(&self, cx: &App) -> bool { self.excerpts.read(cx).has_deleted_file(cx) } - fn has_conflict(&self, cx: &AppContext) -> bool { + fn has_conflict(&self, cx: &App) -> bool { self.excerpts.read(cx).has_conflict(cx) } - fn can_save(&self, _: &AppContext) -> bool { + fn can_save(&self, _: &App) -> bool { true } fn save( &mut self, format: bool, - project: Model, - cx: &mut ViewContext, + project: Entity, + window: &mut Window, + cx: &mut Context, ) -> Task> { - self.editor.save(format, project, cx) + self.editor.save(format, project, window, cx) } fn save_as( &mut self, - _: Model, + _: Entity, _: ProjectPath, - _: &mut ViewContext, + _window: &mut Window, + _: &mut Context, ) -> Task> { unreachable!() } - fn reload(&mut self, project: Model, cx: &mut ViewContext) -> Task> { - self.editor.reload(project, cx) + fn reload( + &mut self, + project: Entity, + window: &mut Window, + cx: &mut Context, + ) -> Task> { + self.editor.reload(project, window, cx) } fn act_as_type<'a>( &'a self, type_id: TypeId, - self_handle: &'a View, - _: &'a AppContext, + self_handle: &'a Entity, + _: &'a App, ) -> Option { if type_id == TypeId::of::() { Some(self_handle.to_any()) @@ -810,21 +856,27 @@ impl Item for ProjectDiagnosticsEditor { } } - fn as_searchable(&self, _: &View) -> Option> { + fn as_searchable(&self, _: &Entity) -> Option> { Some(Box::new(self.editor.clone())) } - fn breadcrumb_location(&self, _: &AppContext) -> ToolbarItemLocation { + fn breadcrumb_location(&self, _: &App) -> ToolbarItemLocation { ToolbarItemLocation::PrimaryLeft } - fn breadcrumbs(&self, theme: &theme::Theme, cx: &AppContext) -> Option> { + fn breadcrumbs(&self, theme: &theme::Theme, cx: &App) -> Option> { self.editor.breadcrumbs(theme, cx) } - fn added_to_workspace(&mut self, workspace: &mut Workspace, cx: &mut ViewContext) { - self.editor - .update(cx, |editor, cx| editor.added_to_workspace(workspace, cx)); + fn added_to_workspace( + &mut self, + workspace: &mut Workspace, + window: &mut Window, + cx: &mut Context, + ) { + self.editor.update(cx, |editor, cx| { + editor.added_to_workspace(workspace, window, cx) + }); } } @@ -840,7 +892,7 @@ fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock { h_flex() .id(DIAGNOSTIC_HEADER) .block_mouse_down() - .h(2. * cx.line_height()) + .h(2. * cx.window.line_height()) .w_full() .px_9() .justify_between() @@ -854,7 +906,7 @@ fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock { .map(|stack| { stack.child( svg() - .size(cx.text_style().font_size) + .size(cx.window.text_style().font_size) .flex_none() .map(|icon| { if diagnostic.severity == DiagnosticSeverity::ERROR { @@ -872,7 +924,7 @@ fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock { .gap_1() .child( StyledText::new(message.clone()).with_highlights( - &cx.text_style(), + &cx.window.text_style(), code_ranges .iter() .map(|range| (range.clone(), highlight_style)), @@ -929,7 +981,7 @@ fn context_range_for_entry( entry: &DiagnosticEntry, context: u32, snapshot: &BufferSnapshot, - cx: &AppContext, + cx: &App, ) -> Range { if let Some(rows) = heuristic_syntactic_expand( entry.range.clone(), @@ -960,7 +1012,7 @@ fn heuristic_syntactic_expand<'a>( input_range: Range, max_row_count: u32, snapshot: &'a BufferSnapshot, - cx: &'a AppContext, + cx: &'a App, ) -> Option> { let input_row_count = input_range.end.row - input_range.start.row; if input_row_count > max_row_count { diff --git a/crates/diagnostics/src/diagnostics_tests.rs b/crates/diagnostics/src/diagnostics_tests.rs index 804be2e6b8..705c70e982 100644 --- a/crates/diagnostics/src/diagnostics_tests.rs +++ b/crates/diagnostics/src/diagnostics_tests.rs @@ -61,7 +61,7 @@ async fn test_diagnostics(cx: &mut TestAppContext) { let language_server_id = LanguageServerId(0); let project = Project::test(fs.clone(), ["/test".as_ref()], cx).await; let lsp_store = project.read_with(cx, |project, _| project.lsp_store()); - let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); + let window = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx)); let cx = &mut VisualTestContext::from_window(*window, cx); let workspace = window.root(cx).unwrap(); @@ -150,18 +150,20 @@ async fn test_diagnostics(cx: &mut TestAppContext) { }); // Open the project diagnostics view while there are already diagnostics. - let view = window.build_view(cx, |cx| { + let diagnostics = window.build_model(cx, |window, cx| { ProjectDiagnosticsEditor::new_with_context( 1, true, project.clone(), workspace.downgrade(), + window, cx, ) }); - let editor = view.update(cx, |view, _| view.editor.clone()); + let editor = diagnostics.update(cx, |diagnostics, _| diagnostics.editor.clone()); - view.next_notification(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10), cx) + diagnostics + .next_notification(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10), cx) .await; assert_eq!( editor_blocks(&editor, cx), @@ -251,7 +253,8 @@ async fn test_diagnostics(cx: &mut TestAppContext) { lsp_store.disk_based_diagnostics_finished(language_server_id, cx); }); - view.next_notification(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10), cx) + diagnostics + .next_notification(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10), cx) .await; assert_eq!( editor_blocks(&editor, cx), @@ -370,7 +373,8 @@ async fn test_diagnostics(cx: &mut TestAppContext) { lsp_store.disk_based_diagnostics_finished(language_server_id, cx); }); - view.next_notification(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10), cx) + diagnostics + .next_notification(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10), cx) .await; assert_eq!( editor_blocks(&editor, cx), @@ -477,20 +481,21 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) { let server_id_2 = LanguageServerId(101); let project = Project::test(fs.clone(), ["/test".as_ref()], cx).await; let lsp_store = project.read_with(cx, |project, _| project.lsp_store()); - let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); + let window = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx)); let cx = &mut VisualTestContext::from_window(*window, cx); let workspace = window.root(cx).unwrap(); - let view = window.build_view(cx, |cx| { + let diagnostics = window.build_model(cx, |window, cx| { ProjectDiagnosticsEditor::new_with_context( 1, true, project.clone(), workspace.downgrade(), + window, cx, ) }); - let editor = view.update(cx, |view, _| view.editor.clone()); + let editor = diagnostics.update(cx, |diagnostics, _| diagnostics.editor.clone()); // Two language servers start updating diagnostics lsp_store.update(cx, |lsp_store, cx| { @@ -754,25 +759,26 @@ async fn test_random_diagnostics(cx: &mut TestAppContext, mut rng: StdRng) { let project = Project::test(fs.clone(), ["/test".as_ref()], cx).await; let lsp_store = project.read_with(cx, |project, _| project.lsp_store()); - let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); + let window = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx)); let cx = &mut VisualTestContext::from_window(*window, cx); let workspace = window.root(cx).unwrap(); - let mutated_view = window.build_view(cx, |cx| { + let mutated_diagnostics = window.build_model(cx, |window, cx| { ProjectDiagnosticsEditor::new_with_context( 1, true, project.clone(), workspace.downgrade(), + window, cx, ) }); - workspace.update(cx, |workspace, cx| { - workspace.add_item_to_center(Box::new(mutated_view.clone()), cx); + workspace.update_in(cx, |workspace, window, cx| { + workspace.add_item_to_center(Box::new(mutated_diagnostics.clone()), window, cx); }); - mutated_view.update(cx, |view, cx| { - assert!(view.focus_handle.is_focused(cx)); + mutated_diagnostics.update_in(cx, |diagnostics, window, _cx| { + assert!(diagnostics.focus_handle.is_focused(window)); }); let mut next_group_id = 0; @@ -858,16 +864,19 @@ async fn test_random_diagnostics(cx: &mut TestAppContext, mut rng: StdRng) { } log::info!("updating mutated diagnostics view"); - mutated_view.update(cx, |view, cx| view.update_stale_excerpts(cx)); + mutated_diagnostics.update_in(cx, |diagnostics, window, cx| { + diagnostics.update_stale_excerpts(window, cx) + }); cx.run_until_parked(); log::info!("constructing reference diagnostics view"); - let reference_view = window.build_view(cx, |cx| { + let reference_diagnostics = window.build_model(cx, |window, cx| { ProjectDiagnosticsEditor::new_with_context( 1, true, project.clone(), workspace.downgrade(), + window, cx, ) }); @@ -875,8 +884,8 @@ async fn test_random_diagnostics(cx: &mut TestAppContext, mut rng: StdRng) { .advance_clock(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10)); cx.run_until_parked(); - let mutated_excerpts = get_diagnostics_excerpts(&mutated_view, cx); - let reference_excerpts = get_diagnostics_excerpts(&reference_view, cx); + let mutated_excerpts = get_diagnostics_excerpts(&mutated_diagnostics, cx); + let reference_excerpts = get_diagnostics_excerpts(&reference_diagnostics, cx); for ((path, language_server_id), diagnostics) in current_diagnostics { for diagnostic in diagnostics { @@ -917,13 +926,13 @@ struct ExcerptInfo { } fn get_diagnostics_excerpts( - view: &View, + diagnostics: &Entity, cx: &mut VisualTestContext, ) -> Vec { - view.update(cx, |view, cx| { + diagnostics.update(cx, |diagnostics, cx| { let mut result = vec![]; let mut excerpt_indices_by_id = HashMap::default(); - view.excerpts.update(cx, |multibuffer, cx| { + diagnostics.excerpts.update(cx, |multibuffer, cx| { let snapshot = multibuffer.snapshot(cx); for (id, buffer, range) in snapshot.excerpts() { excerpt_indices_by_id.insert(id, result.len()); @@ -940,7 +949,7 @@ fn get_diagnostics_excerpts( } }); - for state in &view.path_states { + for state in &diagnostics.path_states { for group in &state.diagnostic_groups { for (ix, excerpt_id) in group.excerpts.iter().enumerate() { let excerpt_ix = excerpt_indices_by_id[excerpt_id]; @@ -1043,58 +1052,63 @@ const FILE_HEADER: &str = "file header"; const EXCERPT_HEADER: &str = "excerpt header"; fn editor_blocks( - editor: &View, + editor: &Entity, cx: &mut VisualTestContext, ) -> Vec<(DisplayRow, SharedString)> { let mut blocks = Vec::new(); - cx.draw(gpui::Point::default(), AvailableSpace::min_size(), |cx| { - editor.update(cx, |editor, cx| { - let snapshot = editor.snapshot(cx); - blocks.extend( - snapshot - .blocks_in_range(DisplayRow(0)..snapshot.max_point().row()) - .filter_map(|(row, block)| { - let block_id = block.id(); - let name: SharedString = match block { - Block::Custom(block) => { - let mut element = block.render(&mut BlockContext { - context: cx, - anchor_x: px(0.), - gutter_dimensions: &GutterDimensions::default(), - line_height: px(0.), - em_width: px(0.), - max_width: px(0.), - block_id, - selected: false, - editor_style: &editor::EditorStyle::default(), - }); - let element = element.downcast_mut::>().unwrap(); - element - .interactivity() - .element_id - .clone()? - .try_into() - .ok()? - } - - Block::FoldedBuffer { .. } => FILE_HEADER.into(), - Block::ExcerptBoundary { - starts_new_buffer, .. - } => { - if *starts_new_buffer { - FILE_HEADER.into() - } else { - EXCERPT_HEADER.into() + cx.draw( + gpui::Point::default(), + AvailableSpace::min_size(), + |window, cx| { + editor.update(cx, |editor, cx| { + let snapshot = editor.snapshot(window, cx); + blocks.extend( + snapshot + .blocks_in_range(DisplayRow(0)..snapshot.max_point().row()) + .filter_map(|(row, block)| { + let block_id = block.id(); + let name: SharedString = match block { + Block::Custom(block) => { + let mut element = block.render(&mut BlockContext { + app: cx, + window, + anchor_x: px(0.), + gutter_dimensions: &GutterDimensions::default(), + line_height: px(0.), + em_width: px(0.), + max_width: px(0.), + block_id, + selected: false, + editor_style: &editor::EditorStyle::default(), + }); + let element = element.downcast_mut::>().unwrap(); + element + .interactivity() + .element_id + .clone()? + .try_into() + .ok()? } - } - }; - Some((row, name)) - }), - ) - }); + Block::FoldedBuffer { .. } => FILE_HEADER.into(), + Block::ExcerptBoundary { + starts_new_buffer, .. + } => { + if *starts_new_buffer { + FILE_HEADER.into() + } else { + EXCERPT_HEADER.into() + } + } + }; - div().into_any() - }); + Some((row, name)) + }), + ) + }); + + div().into_any() + }, + ); blocks } diff --git a/crates/diagnostics/src/items.rs b/crates/diagnostics/src/items.rs index a7c916fecc..bf3e1c7595 100644 --- a/crates/diagnostics/src/items.rs +++ b/crates/diagnostics/src/items.rs @@ -2,8 +2,8 @@ use std::time::Duration; use editor::Editor; use gpui::{ - EventEmitter, IntoElement, ParentElement, Render, Styled, Subscription, Task, View, - ViewContext, WeakView, + Context, Entity, EventEmitter, IntoElement, ParentElement, Render, Styled, Subscription, Task, + WeakEntity, Window, }; use language::Diagnostic; use ui::{h_flex, prelude::*, Button, ButtonLike, Color, Icon, IconName, Label, Tooltip}; @@ -13,15 +13,15 @@ use crate::{Deploy, ProjectDiagnosticsEditor}; pub struct DiagnosticIndicator { summary: project::DiagnosticSummary, - active_editor: Option>, - workspace: WeakView, + active_editor: Option>, + workspace: WeakEntity, current_diagnostic: Option, _observe_active_editor: Option, diagnostics_update: Task<()>, } impl Render for DiagnosticIndicator { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { let diagnostic_indicator = match (self.summary.error_count, self.summary.warning_count) { (0, 0) => h_flex().map(|this| { this.child( @@ -67,11 +67,16 @@ impl Render for DiagnosticIndicator { Some( Button::new("diagnostic_message", message) .label_size(LabelSize::Small) - .tooltip(|cx| { - Tooltip::for_action("Next Diagnostic", &editor::actions::GoToDiagnostic, cx) + .tooltip(|window, cx| { + Tooltip::for_action( + "Next Diagnostic", + &editor::actions::GoToDiagnostic, + window, + cx, + ) }) - .on_click(cx.listener(|this, _, cx| { - this.go_to_next_diagnostic(cx); + .on_click(cx.listener(|this, _, window, cx| { + this.go_to_next_diagnostic(window, cx); })) .into_any_element(), ) @@ -87,11 +92,18 @@ impl Render for DiagnosticIndicator { .child( ButtonLike::new("diagnostic-indicator") .child(diagnostic_indicator) - .tooltip(|cx| Tooltip::for_action("Project Diagnostics", &Deploy, cx)) - .on_click(cx.listener(|this, _, cx| { + .tooltip(|window, cx| { + Tooltip::for_action("Project Diagnostics", &Deploy, window, cx) + }) + .on_click(cx.listener(|this, _, window, cx| { if let Some(workspace) = this.workspace.upgrade() { workspace.update(cx, |workspace, cx| { - ProjectDiagnosticsEditor::deploy(workspace, &Default::default(), cx) + ProjectDiagnosticsEditor::deploy( + workspace, + &Default::default(), + window, + cx, + ) }) } })), @@ -101,7 +113,7 @@ impl Render for DiagnosticIndicator { } impl DiagnosticIndicator { - pub fn new(workspace: &Workspace, cx: &mut ViewContext) -> Self { + pub fn new(workspace: &Workspace, cx: &mut Context) -> Self { let project = workspace.project(); cx.subscribe(project, |this, project, event, cx| match event { project::Event::DiskBasedDiagnosticsStarted { .. } => { @@ -133,15 +145,15 @@ impl DiagnosticIndicator { } } - fn go_to_next_diagnostic(&mut self, cx: &mut ViewContext) { + fn go_to_next_diagnostic(&mut self, window: &mut Window, cx: &mut Context) { if let Some(editor) = self.active_editor.as_ref().and_then(|e| e.upgrade()) { editor.update(cx, |editor, cx| { - editor.go_to_diagnostic_impl(editor::Direction::Next, cx); + editor.go_to_diagnostic_impl(editor::Direction::Next, window, cx); }) } } - fn update(&mut self, editor: View, cx: &mut ViewContext) { + fn update(&mut self, editor: Entity, window: &mut Window, cx: &mut Context) { let (buffer, cursor_position) = editor.update(cx, |editor, cx| { let buffer = editor.buffer().read(cx).snapshot(cx); let cursor_position = editor.selections.newest::(cx).head(); @@ -153,17 +165,18 @@ impl DiagnosticIndicator { .min_by_key(|entry| (entry.diagnostic.severity, entry.range.len())) .map(|entry| entry.diagnostic); if new_diagnostic != self.current_diagnostic { - self.diagnostics_update = cx.spawn(|diagnostics_indicator, mut cx| async move { - cx.background_executor() - .timer(Duration::from_millis(50)) - .await; - diagnostics_indicator - .update(&mut cx, |diagnostics_indicator, cx| { - diagnostics_indicator.current_diagnostic = new_diagnostic; - cx.notify(); - }) - .ok(); - }); + self.diagnostics_update = + cx.spawn_in(window, |diagnostics_indicator, mut cx| async move { + cx.background_executor() + .timer(Duration::from_millis(50)) + .await; + diagnostics_indicator + .update(&mut cx, |diagnostics_indicator, cx| { + diagnostics_indicator.current_diagnostic = new_diagnostic; + cx.notify(); + }) + .ok(); + }); } } } @@ -174,12 +187,13 @@ impl StatusItemView for DiagnosticIndicator { fn set_active_pane_item( &mut self, active_pane_item: Option<&dyn ItemHandle>, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if let Some(editor) = active_pane_item.and_then(|item| item.downcast::()) { self.active_editor = Some(editor.downgrade()); - self._observe_active_editor = Some(cx.observe(&editor, Self::update)); - self.update(editor, cx); + self._observe_active_editor = Some(cx.observe_in(&editor, window, Self::update)); + self.update(editor, window, cx); } else { self.active_editor = None; self.current_diagnostic = None; diff --git a/crates/diagnostics/src/project_diagnostics_settings.rs b/crates/diagnostics/src/project_diagnostics_settings.rs index 55879d0c42..50d0949b73 100644 --- a/crates/diagnostics/src/project_diagnostics_settings.rs +++ b/crates/diagnostics/src/project_diagnostics_settings.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use gpui::AppContext; +use gpui::App; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use settings::{Settings, SettingsSources}; @@ -22,7 +22,7 @@ impl Settings for ProjectDiagnosticsSettings { const KEY: Option<&'static str> = Some("diagnostics"); type FileContent = ProjectDiagnosticsSettingsContent; - fn load(sources: SettingsSources, _: &mut AppContext) -> Result { + fn load(sources: SettingsSources, _: &mut App) -> Result { sources.json_merge() } } diff --git a/crates/diagnostics/src/toolbar_controls.rs b/crates/diagnostics/src/toolbar_controls.rs index f624225e8a..26e4ff20f8 100644 --- a/crates/diagnostics/src/toolbar_controls.rs +++ b/crates/diagnostics/src/toolbar_controls.rs @@ -1,15 +1,15 @@ use crate::ProjectDiagnosticsEditor; -use gpui::{EventEmitter, ParentElement, Render, View, ViewContext, WeakView}; +use gpui::{Context, Entity, EventEmitter, ParentElement, Render, WeakEntity, Window}; use ui::prelude::*; use ui::{IconButton, IconButtonShape, IconName, Tooltip}; use workspace::{item::ItemHandle, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView}; pub struct ToolbarControls { - editor: Option>, + editor: Option>, } impl Render for ToolbarControls { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { let mut include_warnings = false; let mut has_stale_excerpts = false; let mut is_updating = false; @@ -47,11 +47,11 @@ impl Render for ToolbarControls { .icon_color(Color::Info) .shape(IconButtonShape::Square) .disabled(is_updating) - .tooltip(move |cx| Tooltip::text("Update excerpts", cx)) - .on_click(cx.listener(|this, _, cx| { + .tooltip(Tooltip::text("Update excerpts")) + .on_click(cx.listener(|this, _, window, cx| { if let Some(diagnostics) = this.diagnostics() { diagnostics.update(cx, |diagnostics, cx| { - diagnostics.update_all_excerpts(cx); + diagnostics.update_all_excerpts(window, cx); }); } })), @@ -61,11 +61,11 @@ impl Render for ToolbarControls { IconButton::new("toggle-warnings", IconName::Warning) .icon_color(warning_color) .shape(IconButtonShape::Square) - .tooltip(move |cx| Tooltip::text(tooltip, cx)) - .on_click(cx.listener(|this, _, cx| { + .tooltip(Tooltip::text(tooltip)) + .on_click(cx.listener(|this, _, window, cx| { if let Some(editor) = this.diagnostics() { editor.update(cx, |editor, cx| { - editor.toggle_warnings(&Default::default(), cx); + editor.toggle_warnings(&Default::default(), window, cx); }); } })), @@ -79,7 +79,8 @@ impl ToolbarItemView for ToolbarControls { fn set_active_pane_item( &mut self, active_pane_item: Option<&dyn ItemHandle>, - _: &mut ViewContext, + _window: &mut Window, + _: &mut Context, ) -> ToolbarItemLocation { if let Some(pane_item) = active_pane_item.as_ref() { if let Some(editor) = pane_item.downcast::() { @@ -105,7 +106,7 @@ impl ToolbarControls { ToolbarControls { editor: None } } - fn diagnostics(&self) -> Option> { + fn diagnostics(&self) -> Option> { self.editor.as_ref()?.upgrade() } } diff --git a/crates/docs_preprocessor/src/main.rs b/crates/docs_preprocessor/src/main.rs index 488b99c55d..f1e862851b 100644 --- a/crates/docs_preprocessor/src/main.rs +++ b/crates/docs_preprocessor/src/main.rs @@ -1,4 +1,4 @@ -use anyhow::{Context, Result}; +use anyhow::{Context as _, Result}; use clap::{Arg, ArgMatches, Command}; use docs_preprocessor::ZedDocsPreprocessor; use mdbook::preprocess::{CmdPreprocessor, Preprocessor}; diff --git a/crates/editor/src/blame_entry_tooltip.rs b/crates/editor/src/blame_entry_tooltip.rs index 3b3d3e4630..755f63cc40 100644 --- a/crates/editor/src/blame_entry_tooltip.rs +++ b/crates/editor/src/blame_entry_tooltip.rs @@ -2,8 +2,8 @@ use futures::Future; use git::blame::BlameEntry; use git::Oid; use gpui::{ - AppContext, Asset, ClipboardItem, Element, ParentElement, Render, ScrollHandle, - StatefulInteractiveElement, WeakView, + App, Asset, ClipboardItem, Element, ParentElement, Render, ScrollHandle, + StatefulInteractiveElement, WeakEntity, }; use settings::Settings; use std::hash::Hash; @@ -27,7 +27,11 @@ impl<'a> CommitAvatar<'a> { } impl<'a> CommitAvatar<'a> { - fn render(&'a self, cx: &mut ViewContext) -> Option { + fn render( + &'a self, + window: &mut Window, + cx: &mut Context, + ) -> Option { let remote = self .details .and_then(|details| details.remote.as_ref()) @@ -35,7 +39,7 @@ impl<'a> CommitAvatar<'a> { let avatar_url = CommitAvatarAsset::new(remote.clone(), self.sha); - let element = match cx.use_asset::(&avatar_url) { + let element = match window.use_asset::(&avatar_url, cx) { // Loading or no avatar found None | Some(None) => Icon::new(IconName::Person) .color(Color::Muted) @@ -73,7 +77,7 @@ impl Asset for CommitAvatarAsset { fn load( source: Self::Source, - cx: &mut AppContext, + cx: &mut App, ) -> impl Future + Send + 'static { let client = cx.http_client(); @@ -91,7 +95,7 @@ pub(crate) struct BlameEntryTooltip { blame_entry: BlameEntry, details: Option, editor_style: EditorStyle, - workspace: Option>, + workspace: Option>, scroll_handle: ScrollHandle, } @@ -100,7 +104,7 @@ impl BlameEntryTooltip { blame_entry: BlameEntry, details: Option, style: &EditorStyle, - workspace: Option>, + workspace: Option>, ) -> Self { Self { editor_style: style.clone(), @@ -113,8 +117,9 @@ impl BlameEntryTooltip { } impl Render for BlameEntryTooltip { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { - let avatar = CommitAvatar::new(self.details.as_ref(), self.blame_entry.sha).render(cx); + fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { + let avatar = + CommitAvatar::new(self.details.as_ref(), self.blame_entry.sha).render(window, cx); let author = self .blame_entry @@ -149,11 +154,11 @@ impl Render for BlameEntryTooltip { .and_then(|details| details.pull_request.clone()); let ui_font_size = ThemeSettings::get_global(cx).ui_font_size; - let message_max_height = cx.line_height() * 12 + (ui_font_size / 0.4); + let message_max_height = window.line_height() * 12 + (ui_font_size / 0.4); - tooltip_container(cx, move |this, cx| { + tooltip_container(window, cx, move |this, _, cx| { this.occlude() - .on_mouse_move(|_, cx| cx.stop_propagation()) + .on_mouse_move(|_, _, cx| cx.stop_propagation()) .child( v_flex() .w(gpui::rems(30.)) @@ -208,7 +213,7 @@ impl Render for BlameEntryTooltip { .icon_color(Color::Muted) .icon_position(IconPosition::Start) .style(ButtonStyle::Subtle) - .on_click(move |_, cx| { + .on_click(move |_, _, cx| { cx.stop_propagation(); cx.open_url(pr.url.as_str()) }), @@ -235,7 +240,7 @@ impl Render for BlameEntryTooltip { .as_ref() .and_then(|details| details.permalink.clone()), |this, url| { - this.on_click(move |_, cx| { + this.on_click(move |_, _, cx| { cx.stop_propagation(); cx.open_url(url.as_str()) }) @@ -247,7 +252,7 @@ impl Render for BlameEntryTooltip { .shape(IconButtonShape::Square) .icon_size(IconSize::Small) .icon_color(Color::Muted) - .on_click(move |_, cx| { + .on_click(move |_, _, cx| { cx.stop_propagation(); cx.write_to_clipboard( ClipboardItem::new_string(full_sha.clone()), diff --git a/crates/editor/src/blink_manager.rs b/crates/editor/src/blink_manager.rs index 9d828c4de9..3320cf6932 100644 --- a/crates/editor/src/blink_manager.rs +++ b/crates/editor/src/blink_manager.rs @@ -1,5 +1,5 @@ use crate::EditorSettings; -use gpui::ModelContext; +use gpui::Context; use settings::Settings; use settings::SettingsStore; use smol::Timer; @@ -15,7 +15,7 @@ pub struct BlinkManager { } impl BlinkManager { - pub fn new(blink_interval: Duration, cx: &mut ModelContext) -> Self { + pub fn new(blink_interval: Duration, cx: &mut Context) -> Self { // Make sure we blink the cursors if the setting is re-enabled cx.observe_global::(move |this, cx| { this.blink_cursors(this.blink_epoch, cx) @@ -37,7 +37,7 @@ impl BlinkManager { self.blink_epoch } - pub fn pause_blinking(&mut self, cx: &mut ModelContext) { + pub fn pause_blinking(&mut self, cx: &mut Context) { self.show_cursor(cx); let epoch = self.next_blink_epoch(); @@ -49,14 +49,14 @@ impl BlinkManager { .detach(); } - fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut ModelContext) { + fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut Context) { if epoch == self.blink_epoch { self.blinking_paused = false; self.blink_cursors(epoch, cx); } } - fn blink_cursors(&mut self, epoch: usize, cx: &mut ModelContext) { + fn blink_cursors(&mut self, epoch: usize, cx: &mut Context) { if EditorSettings::get_global(cx).cursor_blink { if epoch == self.blink_epoch && self.enabled && !self.blinking_paused { self.visible = !self.visible; @@ -78,14 +78,14 @@ impl BlinkManager { } } - pub fn show_cursor(&mut self, cx: &mut ModelContext<'_, BlinkManager>) { + pub fn show_cursor(&mut self, cx: &mut Context<'_, BlinkManager>) { if !self.visible { self.visible = true; cx.notify(); } } - pub fn enable(&mut self, cx: &mut ModelContext) { + pub fn enable(&mut self, cx: &mut Context) { if self.enabled { return; } @@ -97,7 +97,7 @@ impl BlinkManager { self.blink_cursors(self.blink_epoch, cx); } - pub fn disable(&mut self, _cx: &mut ModelContext) { + pub fn disable(&mut self, _cx: &mut Context) { self.visible = false; self.enabled = false; } diff --git a/crates/editor/src/clangd_ext.rs b/crates/editor/src/clangd_ext.rs index 28aafc1f46..d85e6bedf5 100644 --- a/crates/editor/src/clangd_ext.rs +++ b/crates/editor/src/clangd_ext.rs @@ -1,5 +1,5 @@ use anyhow::Context as _; -use gpui::{View, ViewContext, WindowContext}; +use gpui::{App, Context, Entity, Window}; use language::Language; use url::Url; @@ -16,7 +16,8 @@ fn is_c_language(language: &Language) -> bool { pub fn switch_source_header( editor: &mut Editor, _: &SwitchSourceHeader, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let Some(project) = &editor.project else { return; @@ -49,7 +50,7 @@ pub fn switch_source_header( cx, ) }); - cx.spawn(|_editor, mut cx| async move { + cx.spawn_in(window, |_editor, mut cx| async move { let switch_source_header = switch_source_header_task .await .with_context(|| format!("Switch source/header LSP request for path \"{source_file}\" failed"))?; @@ -70,8 +71,8 @@ pub fn switch_source_header( })?; workspace - .update(&mut cx, |workspace, view_cx| { - workspace.open_abs_path(path, false, view_cx) + .update_in(&mut cx, |workspace, window, cx| { + workspace.open_abs_path(path, false, window, cx) }) .with_context(|| { format!( @@ -84,11 +85,11 @@ pub fn switch_source_header( .detach_and_log_err(cx); } -pub fn apply_related_actions(editor: &View, cx: &mut WindowContext) { +pub fn apply_related_actions(editor: &Entity, window: &mut Window, cx: &mut App) { if editor.update(cx, |e, cx| { find_specific_language_server_in_selection(e, cx, is_c_language, CLANGD_SERVER_NAME) .is_some() }) { - register_action(editor, cx, switch_source_header); + register_action(editor, window, switch_source_header); } } diff --git a/crates/editor/src/code_context_menus.rs b/crates/editor/src/code_context_menus.rs index a9429995d8..f513c20689 100644 --- a/crates/editor/src/code_context_menus.rs +++ b/crates/editor/src/code_context_menus.rs @@ -1,8 +1,8 @@ use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ div, pulsating_between, px, uniform_list, Animation, AnimationExt, AnyElement, - BackgroundExecutor, Div, FontWeight, ListSizingBehavior, Model, ScrollStrategy, SharedString, - Size, StrikethroughStyle, StyledText, UniformListScrollHandle, ViewContext, WeakView, + BackgroundExecutor, Div, Entity, FontWeight, ListSizingBehavior, ScrollStrategy, SharedString, + Size, StrikethroughStyle, StyledText, UniformListScrollHandle, WeakEntity, }; use language::Buffer; use language::{CodeLabel, Documentation}; @@ -46,7 +46,7 @@ impl CodeContextMenu { pub fn select_first( &mut self, provider: Option<&dyn CompletionProvider>, - cx: &mut ViewContext, + cx: &mut Context, ) -> bool { if self.visible() { match self { @@ -62,7 +62,7 @@ impl CodeContextMenu { pub fn select_prev( &mut self, provider: Option<&dyn CompletionProvider>, - cx: &mut ViewContext, + cx: &mut Context, ) -> bool { if self.visible() { match self { @@ -78,7 +78,7 @@ impl CodeContextMenu { pub fn select_next( &mut self, provider: Option<&dyn CompletionProvider>, - cx: &mut ViewContext, + cx: &mut Context, ) -> bool { if self.visible() { match self { @@ -94,7 +94,7 @@ impl CodeContextMenu { pub fn select_last( &mut self, provider: Option<&dyn CompletionProvider>, - cx: &mut ViewContext, + cx: &mut Context, ) -> bool { if self.visible() { match self { @@ -126,14 +126,15 @@ impl CodeContextMenu { style: &EditorStyle, max_height_in_lines: u32, y_flipped: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> AnyElement { match self { CodeContextMenu::Completions(menu) => { - menu.render(style, max_height_in_lines, y_flipped, cx) + menu.render(style, max_height_in_lines, y_flipped, window, cx) } CodeContextMenu::CodeActions(menu) => { - menu.render(style, max_height_in_lines, y_flipped, cx) + menu.render(style, max_height_in_lines, y_flipped, window, cx) } } } @@ -142,8 +143,8 @@ impl CodeContextMenu { &self, style: &EditorStyle, max_size: Size, - workspace: Option>, - cx: &mut ViewContext, + workspace: Option>, + cx: &mut Context, ) -> Option { match self { CodeContextMenu::Completions(menu) => menu.render_aside(style, max_size, workspace, cx), @@ -162,7 +163,7 @@ pub struct CompletionsMenu { pub id: CompletionId, sort_completions: bool, pub initial_position: Anchor, - pub buffer: Model, + pub buffer: Entity, pub completions: Rc>>, match_candidates: Rc<[StringMatchCandidate]>, pub entries: Rc>>, @@ -185,7 +186,7 @@ impl CompletionsMenu { sort_completions: bool, show_completion_documentation: bool, initial_position: Anchor, - buffer: Model, + buffer: Entity, completions: Box<[Completion]>, ) -> Self { let match_candidates = completions @@ -215,7 +216,7 @@ impl CompletionsMenu { sort_completions: bool, choices: &Vec, selection: Range, - buffer: Model, + buffer: Entity, ) -> Self { let completions = choices .iter() @@ -271,7 +272,7 @@ impl CompletionsMenu { fn select_first( &mut self, provider: Option<&dyn CompletionProvider>, - cx: &mut ViewContext, + cx: &mut Context, ) { let index = if self.scroll_handle.y_flipped() { self.entries.borrow().len() - 1 @@ -281,11 +282,7 @@ impl CompletionsMenu { self.update_selection_index(index, provider, cx); } - fn select_last( - &mut self, - provider: Option<&dyn CompletionProvider>, - cx: &mut ViewContext, - ) { + fn select_last(&mut self, provider: Option<&dyn CompletionProvider>, cx: &mut Context) { let index = if self.scroll_handle.y_flipped() { 0 } else { @@ -294,11 +291,7 @@ impl CompletionsMenu { self.update_selection_index(index, provider, cx); } - fn select_prev( - &mut self, - provider: Option<&dyn CompletionProvider>, - cx: &mut ViewContext, - ) { + fn select_prev(&mut self, provider: Option<&dyn CompletionProvider>, cx: &mut Context) { let index = if self.scroll_handle.y_flipped() { self.next_match_index() } else { @@ -307,11 +300,7 @@ impl CompletionsMenu { self.update_selection_index(index, provider, cx); } - fn select_next( - &mut self, - provider: Option<&dyn CompletionProvider>, - cx: &mut ViewContext, - ) { + fn select_next(&mut self, provider: Option<&dyn CompletionProvider>, cx: &mut Context) { let index = if self.scroll_handle.y_flipped() { self.prev_match_index() } else { @@ -324,7 +313,7 @@ impl CompletionsMenu { &mut self, match_index: usize, provider: Option<&dyn CompletionProvider>, - cx: &mut ViewContext, + cx: &mut Context, ) { if self.selected_item != match_index { self.selected_item = match_index; @@ -372,7 +361,7 @@ impl CompletionsMenu { pub fn resolve_visible_completions( &mut self, provider: Option<&dyn CompletionProvider>, - cx: &mut ViewContext, + cx: &mut Context, ) { if !self.resolve_completions { return; @@ -469,7 +458,8 @@ impl CompletionsMenu { style: &EditorStyle, max_height_in_lines: u32, y_flipped: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> AnyElement { let completions = self.completions.borrow_mut(); let show_completion_documentation = self.show_completion_documentation; @@ -505,10 +495,10 @@ impl CompletionsMenu { let last_rendered_range = self.last_rendered_range.clone(); let style = style.clone(); let list = uniform_list( - cx.view().clone(), + cx.model().clone(), "completions", self.entries.borrow().len(), - move |_editor, range, cx| { + move |_editor, range, _window, cx| { last_rendered_range.borrow_mut().replace(range.clone()); let start_ix = range.start; let completions_guard = completions.borrow_mut(); @@ -591,12 +581,13 @@ impl CompletionsMenu { ListItem::new(mat.candidate_id) .inset(true) .toggle_state(item_ix == selected_item) - .on_click(cx.listener(move |editor, _event, cx| { + .on_click(cx.listener(move |editor, _event, window, cx| { cx.stop_propagation(); if let Some(task) = editor.confirm_completion( &ConfirmCompletion { item_ix: Some(item_ix), }, + window, cx, ) { task.detach_and_log_err(cx) @@ -659,9 +650,9 @@ impl CompletionsMenu { .with_highlights(&style.text, None), ), ) - .on_click(cx.listener(move |editor, _event, cx| { + .on_click(cx.listener(move |editor, _event, window, cx| { cx.stop_propagation(); - editor.toggle_zed_predict_tos(cx); + editor.toggle_zed_predict_tos(window, cx); })), ), @@ -678,10 +669,11 @@ impl CompletionsMenu { .with_highlights(&style.text, None), ), ) - .on_click(cx.listener(move |editor, _event, cx| { + .on_click(cx.listener(move |editor, _event, window, cx| { cx.stop_propagation(); editor.accept_inline_completion( &AcceptInlineCompletion {}, + window, cx, ); })), @@ -692,7 +684,7 @@ impl CompletionsMenu { }, ) .occlude() - .max_h(max_height_in_lines as f32 * cx.line_height()) + .max_h(max_height_in_lines as f32 * window.line_height()) .track_scroll(self.scroll_handle.clone()) .y_flipped(y_flipped) .with_width_from_item(widest_completion_ix) @@ -705,8 +697,8 @@ impl CompletionsMenu { &self, style: &EditorStyle, max_size: Size, - workspace: Option>, - cx: &mut ViewContext, + workspace: Option>, + cx: &mut Context, ) -> Option { if !self.show_completion_documentation { return None; @@ -1008,14 +1000,14 @@ impl CodeActionsItem { pub struct CodeActionsMenu { pub actions: CodeActionContents, - pub buffer: Model, + pub buffer: Entity, pub selected_item: usize, pub scroll_handle: UniformListScrollHandle, pub deployed_from_indicator: Option, } impl CodeActionsMenu { - fn select_first(&mut self, cx: &mut ViewContext) { + fn select_first(&mut self, cx: &mut Context) { self.selected_item = if self.scroll_handle.y_flipped() { self.actions.len() - 1 } else { @@ -1026,7 +1018,7 @@ impl CodeActionsMenu { cx.notify() } - fn select_last(&mut self, cx: &mut ViewContext) { + fn select_last(&mut self, cx: &mut Context) { self.selected_item = if self.scroll_handle.y_flipped() { 0 } else { @@ -1037,7 +1029,7 @@ impl CodeActionsMenu { cx.notify() } - fn select_prev(&mut self, cx: &mut ViewContext) { + fn select_prev(&mut self, cx: &mut Context) { self.selected_item = if self.scroll_handle.y_flipped() { self.next_match_index() } else { @@ -1048,7 +1040,7 @@ impl CodeActionsMenu { cx.notify(); } - fn select_next(&mut self, cx: &mut ViewContext) { + fn select_next(&mut self, cx: &mut Context) { self.selected_item = if self.scroll_handle.y_flipped() { self.prev_match_index() } else { @@ -1092,15 +1084,16 @@ impl CodeActionsMenu { _style: &EditorStyle, max_height_in_lines: u32, y_flipped: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> AnyElement { let actions = self.actions.clone(); let selected_item = self.selected_item; let list = uniform_list( - cx.view().clone(), + cx.model().clone(), "code_actions_menu", self.actions.len(), - move |_this, range, cx| { + move |_this, range, _, cx| { actions .iter() .skip(range.start) @@ -1115,12 +1108,13 @@ impl CodeActionsMenu { .inset(true) .toggle_state(selected) .when_some(action.as_code_action(), |this, action| { - this.on_click(cx.listener(move |editor, _, cx| { + this.on_click(cx.listener(move |editor, _, window, cx| { cx.stop_propagation(); if let Some(task) = editor.confirm_code_action( &ConfirmCodeAction { item_ix: Some(item_ix), }, + window, cx, ) { task.detach_and_log_err(cx) @@ -1139,12 +1133,13 @@ impl CodeActionsMenu { ) }) .when_some(action.as_task(), |this, task| { - this.on_click(cx.listener(move |editor, _, cx| { + this.on_click(cx.listener(move |editor, _, window, cx| { cx.stop_propagation(); if let Some(task) = editor.confirm_code_action( &ConfirmCodeAction { item_ix: Some(item_ix), }, + window, cx, ) { task.detach_and_log_err(cx) @@ -1165,7 +1160,7 @@ impl CodeActionsMenu { }, ) .occlude() - .max_h(max_height_in_lines as f32 * cx.line_height()) + .max_h(max_height_in_lines as f32 * window.line_height()) .track_scroll(self.scroll_handle.clone()) .y_flipped(y_flipped) .with_width_from_item( diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index 34bdaf4b72..b9d59d65df 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -39,10 +39,7 @@ use collections::{HashMap, HashSet}; pub use crease_map::*; pub use fold_map::{Fold, FoldId, FoldPlaceholder, FoldPoint}; use fold_map::{FoldMap, FoldSnapshot}; -use gpui::{ - AnyElement, AppContext, Font, HighlightStyle, LineLayout, Model, ModelContext, Pixels, - UnderlineStyle, -}; +use gpui::{App, Context, Entity, Font, HighlightStyle, LineLayout, Pixels, UnderlineStyle}; pub use inlay_map::Inlay; use inlay_map::{InlayMap, InlaySnapshot}; pub use inlay_map::{InlayOffset, InlayPoint}; @@ -69,7 +66,7 @@ use std::{ use sum_tree::{Bias, TreeMap}; use tab_map::{TabMap, TabSnapshot}; use text::{BufferId, LineIndent}; -use ui::{px, SharedString, WindowContext}; +use ui::{px, SharedString}; use unicode_segmentation::UnicodeSegmentation; use wrap_map::{WrapMap, WrapSnapshot}; @@ -79,8 +76,6 @@ pub enum FoldStatus { Foldable, } -pub type RenderFoldToggle = Arc AnyElement>; - pub trait ToDisplayPoint { fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint; } @@ -94,7 +89,7 @@ type InlayHighlights = TreeMap, + buffer: Entity, buffer_subscription: BufferSubscription, /// Decides where the [`Inlay`]s should be displayed. inlay_map: InlayMap, @@ -103,7 +98,7 @@ pub struct DisplayMap { /// Keeps track of hard tabs in a buffer. tab_map: TabMap, /// Handles soft wrapping. - wrap_map: Model, + wrap_map: Entity, /// Tracks custom blocks such as diagnostics that should be displayed within buffer. block_map: BlockMap, /// Regions of text that should be highlighted. @@ -120,7 +115,7 @@ pub struct DisplayMap { impl DisplayMap { #[allow(clippy::too_many_arguments)] pub fn new( - buffer: Model, + buffer: Entity, font: Font, font_size: Pixels, wrap_width: Option, @@ -129,7 +124,7 @@ impl DisplayMap { excerpt_header_height: u32, excerpt_footer_height: u32, fold_placeholder: FoldPlaceholder, - cx: &mut ModelContext, + cx: &mut Context, ) -> Self { let buffer_subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); @@ -167,7 +162,7 @@ impl DisplayMap { } } - pub fn snapshot(&mut self, cx: &mut ModelContext) -> DisplaySnapshot { + pub fn snapshot(&mut self, cx: &mut Context) -> DisplaySnapshot { let buffer_snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); let (inlay_snapshot, edits) = self.inlay_map.sync(buffer_snapshot, edits); @@ -195,7 +190,7 @@ impl DisplayMap { } } - pub fn set_state(&mut self, other: &DisplaySnapshot, cx: &mut ModelContext) { + pub fn set_state(&mut self, other: &DisplaySnapshot, cx: &mut Context) { self.fold( other .folds_in_range(0..other.buffer_snapshot.len()) @@ -211,11 +206,7 @@ impl DisplayMap { } /// Creates folds for the given creases. - pub fn fold( - &mut self, - creases: Vec>, - cx: &mut ModelContext, - ) { + pub fn fold(&mut self, creases: Vec>, cx: &mut Context) { let buffer_snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); let tab_size = Self::tab_size(&self.buffer, cx); @@ -287,7 +278,7 @@ impl DisplayMap { &mut self, ranges: impl IntoIterator>, type_id: TypeId, - cx: &mut ModelContext, + cx: &mut Context, ) { let snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); @@ -312,7 +303,7 @@ impl DisplayMap { &mut self, ranges: impl IntoIterator>, inclusive: bool, - cx: &mut ModelContext, + cx: &mut Context, ) { let snapshot = self.buffer.read(cx).snapshot(cx); let offset_ranges = ranges @@ -339,7 +330,7 @@ impl DisplayMap { block_map.remove_intersecting_replace_blocks(offset_ranges, inclusive); } - pub fn fold_buffer(&mut self, buffer_id: language::BufferId, cx: &mut ModelContext) { + pub fn fold_buffer(&mut self, buffer_id: language::BufferId, cx: &mut Context) { let snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); let tab_size = Self::tab_size(&self.buffer, cx); @@ -353,7 +344,7 @@ impl DisplayMap { block_map.fold_buffer(buffer_id, self.buffer.read(cx), cx) } - pub fn unfold_buffer(&mut self, buffer_id: language::BufferId, cx: &mut ModelContext) { + pub fn unfold_buffer(&mut self, buffer_id: language::BufferId, cx: &mut Context) { let snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); let tab_size = Self::tab_size(&self.buffer, cx); @@ -378,7 +369,7 @@ impl DisplayMap { pub fn insert_creases( &mut self, creases: impl IntoIterator>, - cx: &mut ModelContext, + cx: &mut Context, ) -> Vec { let snapshot = self.buffer.read(cx).snapshot(cx); self.crease_map.insert(creases, &snapshot) @@ -387,7 +378,7 @@ impl DisplayMap { pub fn remove_creases( &mut self, crease_ids: impl IntoIterator, - cx: &mut ModelContext, + cx: &mut Context, ) { let snapshot = self.buffer.read(cx).snapshot(cx); self.crease_map.remove(crease_ids, &snapshot) @@ -396,7 +387,7 @@ impl DisplayMap { pub fn insert_blocks( &mut self, blocks: impl IntoIterator>, - cx: &mut ModelContext, + cx: &mut Context, ) -> Vec { let snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); @@ -411,11 +402,7 @@ impl DisplayMap { block_map.insert(blocks) } - pub fn resize_blocks( - &mut self, - heights: HashMap, - cx: &mut ModelContext, - ) { + pub fn resize_blocks(&mut self, heights: HashMap, cx: &mut Context) { let snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); let tab_size = Self::tab_size(&self.buffer, cx); @@ -433,7 +420,7 @@ impl DisplayMap { self.block_map.replace_blocks(renderers); } - pub fn remove_blocks(&mut self, ids: HashSet, cx: &mut ModelContext) { + pub fn remove_blocks(&mut self, ids: HashSet, cx: &mut Context) { let snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); let tab_size = Self::tab_size(&self.buffer, cx); @@ -450,7 +437,7 @@ impl DisplayMap { pub fn row_for_block( &mut self, block_id: CustomBlockId, - cx: &mut ModelContext, + cx: &mut Context, ) -> Option { let snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); @@ -505,12 +492,12 @@ impl DisplayMap { cleared } - pub fn set_font(&self, font: Font, font_size: Pixels, cx: &mut ModelContext) -> bool { + pub fn set_font(&self, font: Font, font_size: Pixels, cx: &mut Context) -> bool { self.wrap_map .update(cx, |map, cx| map.set_font_with_size(font, font_size, cx)) } - pub fn set_wrap_width(&self, width: Option, cx: &mut ModelContext) -> bool { + pub fn set_wrap_width(&self, width: Option, cx: &mut Context) -> bool { self.wrap_map .update(cx, |map, cx| map.set_wrap_width(width, cx)) } @@ -523,7 +510,7 @@ impl DisplayMap { &mut self, to_remove: Vec, to_insert: Vec, - cx: &mut ModelContext, + cx: &mut Context, ) { if to_remove.is_empty() && to_insert.is_empty() { return; @@ -548,7 +535,7 @@ impl DisplayMap { self.block_map.read(snapshot, edits); } - fn tab_size(buffer: &Model, cx: &AppContext) -> NonZeroU32 { + fn tab_size(buffer: &Entity, cx: &App) -> NonZeroU32 { let buffer = buffer.read(cx).as_singleton().map(|buffer| buffer.read(cx)); let language = buffer .and_then(|buffer| buffer.language()) @@ -558,7 +545,7 @@ impl DisplayMap { } #[cfg(test)] - pub fn is_rewrapping(&self, cx: &gpui::AppContext) -> bool { + pub fn is_rewrapping(&self, cx: &gpui::App) -> bool { self.wrap_map.read(cx).is_rewrapping() } @@ -1452,7 +1439,7 @@ pub mod tests { use crate::{movement, test::marked_display_snapshot}; use block_map::BlockPlacement; use gpui::{ - div, font, observe, px, AppContext, BorrowAppContext, Context, Element, Hsla, Rgba, + div, font, observe, px, App, AppContext as _, BorrowAppContext, Element, Hsla, Rgba, }; use language::{ language_settings::{AllLanguageSettings, AllLanguageSettingsContent}, @@ -1508,7 +1495,7 @@ pub mod tests { } }); - let map = cx.new_model(|cx| { + let map = cx.new(|cx| { DisplayMap::new( buffer.clone(), font("Helvetica"), @@ -1749,16 +1736,16 @@ pub mod tests { let editor = cx.editor.clone(); let window = cx.window; - _ = cx.update_window(window, |_, cx| { + _ = cx.update_window(window, |_, window, cx| { let text_layout_details = - editor.update(cx, |editor, cx| editor.text_layout_details(cx)); + editor.update(cx, |editor, _cx| editor.text_layout_details(window)); let font_size = px(12.0); let wrap_width = Some(px(64.)); let text = "one two three four five\nsix seven eight"; let buffer = MultiBuffer::build_simple(text, cx); - let map = cx.new_model(|cx| { + let map = cx.new(|cx| { DisplayMap::new( buffer.clone(), font("Helvetica"), @@ -1862,14 +1849,14 @@ pub mod tests { } #[gpui::test] - fn test_text_chunks(cx: &mut gpui::AppContext) { + fn test_text_chunks(cx: &mut gpui::App) { init_test(cx, |_| {}); let text = sample_text(6, 6, 'a'); let buffer = MultiBuffer::build_simple(&text, cx); let font_size = px(14.0); - let map = cx.new_model(|cx| { + let map = cx.new(|cx| { DisplayMap::new( buffer.clone(), font("Helvetica"), @@ -1959,13 +1946,13 @@ pub mod tests { cx.update(|cx| init_test(cx, |s| s.defaults.tab_size = Some(2.try_into().unwrap()))); - let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(language, cx)); cx.condition(&buffer, |buf, _| !buf.is_parsing()).await; - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); let font_size = px(14.0); - let map = cx.new_model(|cx| { + let map = cx.new(|cx| { DisplayMap::new( buffer, font("Helvetica"), @@ -2062,12 +2049,12 @@ pub mod tests { cx.update(|cx| init_test(cx, |_| {})); - let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(language, cx)); cx.condition(&buffer, |buf, _| !buf.is_parsing()).await; - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); let buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx)); - let map = cx.new_model(|cx| { + let map = cx.new(|cx| { DisplayMap::new( buffer, font("Courier"), @@ -2136,7 +2123,7 @@ pub mod tests { cx.update(|cx| init_test(cx, |_| {})); - let buffer = cx.new_model(|cx| Buffer::local(text, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx)); buffer.update(cx, |buffer, cx| { buffer.update_diagnostics( @@ -2157,10 +2144,10 @@ pub mod tests { ) }); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); let buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx)); - let map = cx.new_model(|cx| { + let map = cx.new(|cx| { DisplayMap::new( buffer, font("Courier"), @@ -2249,7 +2236,7 @@ pub mod tests { let buffer = cx.update(|cx| MultiBuffer::build_simple("abcde\nfghij\nklmno\npqrst", cx)); let buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx)); - let map = cx.new_model(|cx| { + let map = cx.new(|cx| { DisplayMap::new( buffer.clone(), font("Courier"), @@ -2387,13 +2374,13 @@ pub mod tests { cx.update(|cx| init_test(cx, |_| {})); - let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(language, cx)); cx.condition(&buffer, |buf, _| !buf.is_parsing()).await; - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); let font_size = px(16.0); - let map = cx.new_model(|cx| { + let map = cx.new(|cx| { DisplayMap::new( buffer, font("Courier"), @@ -2470,14 +2457,14 @@ pub mod tests { let (text, highlighted_ranges) = marked_text_ranges(r#"constˇ «a»: B = "c «d»""#, false); - let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(language, cx)); cx.condition(&buffer, |buf, _| !buf.is_parsing()).await; - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); let buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx)); let font_size = px(16.0); - let map = cx.new_model(|cx| { + let map = cx.new(|cx| { DisplayMap::new( buffer, font("Courier"), @@ -2528,10 +2515,10 @@ pub mod tests { } #[gpui::test] - fn test_clip_point(cx: &mut gpui::AppContext) { + fn test_clip_point(cx: &mut gpui::App) { init_test(cx, |_| {}); - fn assert(text: &str, shift_right: bool, bias: Bias, cx: &mut gpui::AppContext) { + fn assert(text: &str, shift_right: bool, bias: Bias, cx: &mut gpui::App) { let (unmarked_snapshot, mut markers) = marked_display_snapshot(text, cx); match bias { @@ -2578,10 +2565,10 @@ pub mod tests { } #[gpui::test] - fn test_clip_at_line_ends(cx: &mut gpui::AppContext) { + fn test_clip_at_line_ends(cx: &mut gpui::App) { init_test(cx, |_| {}); - fn assert(text: &str, cx: &mut gpui::AppContext) { + fn assert(text: &str, cx: &mut gpui::App) { let (mut unmarked_snapshot, markers) = marked_display_snapshot(text, cx); unmarked_snapshot.clip_at_line_ends = true; assert_eq!( @@ -2597,13 +2584,13 @@ pub mod tests { } #[gpui::test] - fn test_creases(cx: &mut gpui::AppContext) { + fn test_creases(cx: &mut gpui::App) { init_test(cx, |_| {}); let text = "aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll"; let buffer = MultiBuffer::build_simple(text, cx); let font_size = px(14.0); - cx.new_model(|cx| { + cx.new(|cx| { let mut map = DisplayMap::new( buffer.clone(), font("Helvetica"), @@ -2624,8 +2611,8 @@ pub mod tests { [Crease::inline( range, FoldPlaceholder::test(), - |_row, _status, _toggle, _cx| div(), - |_row, _status, _cx| div(), + |_row, _status, _toggle, _window, _cx| div(), + |_row, _status, _window, _cx| div(), )], &map.buffer.read(cx).snapshot(cx), ); @@ -2635,14 +2622,14 @@ pub mod tests { } #[gpui::test] - fn test_tabs_with_multibyte_chars(cx: &mut gpui::AppContext) { + fn test_tabs_with_multibyte_chars(cx: &mut gpui::App) { init_test(cx, |_| {}); let text = "✅\t\tα\nβ\t\n🏀β\t\tγ"; let buffer = MultiBuffer::build_simple(text, cx); let font_size = px(14.0); - let map = cx.new_model(|cx| { + let map = cx.new(|cx| { DisplayMap::new( buffer.clone(), font("Helvetica"), @@ -2714,12 +2701,12 @@ pub mod tests { } #[gpui::test] - fn test_max_point(cx: &mut gpui::AppContext) { + fn test_max_point(cx: &mut gpui::App) { init_test(cx, |_| {}); let buffer = MultiBuffer::build_simple("aaa\n\t\tbbb", cx); let font_size = px(14.0); - let map = cx.new_model(|cx| { + let map = cx.new(|cx| { DisplayMap::new( buffer.clone(), font("Helvetica"), @@ -2741,9 +2728,9 @@ pub mod tests { fn syntax_chunks( rows: Range, - map: &Model, + map: &Entity, theme: &SyntaxTheme, - cx: &mut AppContext, + cx: &mut App, ) -> Vec<(String, Option)> { chunks(rows, map, theme, cx) .into_iter() @@ -2753,9 +2740,9 @@ pub mod tests { fn chunks( rows: Range, - map: &Model, + map: &Entity, theme: &SyntaxTheme, - cx: &mut AppContext, + cx: &mut App, ) -> Vec<(String, Option, Option)> { let snapshot = map.update(cx, |map, cx| map.snapshot(cx)); let mut chunks: Vec<(String, Option, Option)> = Vec::new(); @@ -2775,7 +2762,7 @@ pub mod tests { chunks } - fn init_test(cx: &mut AppContext, f: impl Fn(&mut AllLanguageSettingsContent)) { + fn init_test(cx: &mut App, f: impl Fn(&mut AllLanguageSettingsContent)) { let settings = SettingsStore::test(cx); cx.set_global(settings); language::init(cx); diff --git a/crates/editor/src/display_map/block_map.rs b/crates/editor/src/display_map/block_map.rs index 54bb647232..1470875508 100644 --- a/crates/editor/src/display_map/block_map.rs +++ b/crates/editor/src/display_map/block_map.rs @@ -4,7 +4,7 @@ use super::{ }; use crate::{EditorStyle, GutterDimensions}; use collections::{Bound, HashMap, HashSet}; -use gpui::{AnyElement, AppContext, EntityId, Pixels, WindowContext}; +use gpui::{AnyElement, App, EntityId, Pixels, Window}; use language::{Chunk, Patch, Point}; use multi_buffer::{ Anchor, ExcerptId, ExcerptInfo, MultiBuffer, MultiBufferRow, MultiBufferSnapshot, RowInfo, @@ -226,7 +226,8 @@ pub enum BlockStyle { } pub struct BlockContext<'a, 'b> { - pub context: &'b mut WindowContext<'a>, + pub window: &'a mut Window, + pub app: &'b mut App, pub anchor_x: Pixels, pub max_width: Pixels, pub gutter_dimensions: &'b GutterDimensions, @@ -1232,22 +1233,12 @@ impl<'a> BlockMapWriter<'a> { self.remove(blocks_to_remove); } - pub fn fold_buffer( - &mut self, - buffer_id: BufferId, - multi_buffer: &MultiBuffer, - cx: &AppContext, - ) { + pub fn fold_buffer(&mut self, buffer_id: BufferId, multi_buffer: &MultiBuffer, cx: &App) { self.0.folded_buffers.insert(buffer_id); self.recompute_blocks_for_buffer(buffer_id, multi_buffer, cx); } - pub fn unfold_buffer( - &mut self, - buffer_id: BufferId, - multi_buffer: &MultiBuffer, - cx: &AppContext, - ) { + pub fn unfold_buffer(&mut self, buffer_id: BufferId, multi_buffer: &MultiBuffer, cx: &App) { self.0.folded_buffers.remove(&buffer_id); self.recompute_blocks_for_buffer(buffer_id, multi_buffer, cx); } @@ -1256,7 +1247,7 @@ impl<'a> BlockMapWriter<'a> { &mut self, buffer_id: BufferId, multi_buffer: &MultiBuffer, - cx: &AppContext, + cx: &App, ) { let wrap_snapshot = self.0.wrap_snapshot.borrow().clone(); @@ -1934,16 +1925,16 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for BlockRow { } impl<'a> Deref for BlockContext<'a, '_> { - type Target = WindowContext<'a>; + type Target = App; fn deref(&self) -> &Self::Target { - self.context + self.app } } impl DerefMut for BlockContext<'_, '_> { fn deref_mut(&mut self) -> &mut Self::Target { - self.context + self.app } } @@ -2001,7 +1992,7 @@ mod tests { use crate::display_map::{ fold_map::FoldMap, inlay_map::InlayMap, tab_map::TabMap, wrap_map::WrapMap, }; - use gpui::{div, font, px, AppContext, Context as _, Element}; + use gpui::{div, font, px, App, AppContext as _, Element}; use itertools::Itertools; use language::{Buffer, Capability}; use multi_buffer::{ExcerptRange, MultiBuffer}; @@ -2195,15 +2186,15 @@ mod tests { } #[gpui::test] - fn test_multibuffer_headers_and_footers(cx: &mut AppContext) { + fn test_multibuffer_headers_and_footers(cx: &mut App) { init_test(cx); - let buffer1 = cx.new_model(|cx| Buffer::local("Buffer 1", cx)); - let buffer2 = cx.new_model(|cx| Buffer::local("Buffer 2", cx)); - let buffer3 = cx.new_model(|cx| Buffer::local("Buffer 3", cx)); + let buffer1 = cx.new(|cx| Buffer::local("Buffer 1", cx)); + let buffer2 = cx.new(|cx| Buffer::local("Buffer 2", cx)); + let buffer3 = cx.new(|cx| Buffer::local("Buffer 3", cx)); let mut excerpt_ids = Vec::new(); - let multi_buffer = cx.new_model(|cx| { + let multi_buffer = cx.new(|cx| { let mut multi_buffer = MultiBuffer::new(Capability::ReadWrite); excerpt_ids.extend(multi_buffer.push_excerpts( buffer1.clone(), @@ -3652,7 +3643,7 @@ mod tests { } } - fn init_test(cx: &mut gpui::AppContext) { + fn init_test(cx: &mut gpui::App) { let settings = SettingsStore::test(cx); cx.set_global(settings); theme::init(theme::LoadThemes::JustBase, cx); diff --git a/crates/editor/src/display_map/crease_map.rs b/crates/editor/src/display_map/crease_map.rs index 77d1401e75..af11a30ea0 100644 --- a/crates/editor/src/display_map/crease_map.rs +++ b/crates/editor/src/display_map/crease_map.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use std::{cmp::Ordering, fmt::Debug, ops::Range, sync::Arc}; use sum_tree::{Bias, SeekTarget, SumTree}; use text::Point; -use ui::{IconName, SharedString, WindowContext}; +use ui::{App, IconName, SharedString, Window}; use crate::{BlockStyle, FoldPlaceholder, RenderBlock}; @@ -117,12 +117,13 @@ type RenderToggleFn = Arc< + Fn( MultiBufferRow, bool, - Arc, - &mut WindowContext, + Arc, + &mut Window, + &mut App, ) -> AnyElement, >; type RenderTrailerFn = - Arc AnyElement>; + Arc AnyElement>; #[derive(Clone)] pub enum Crease { @@ -185,26 +186,27 @@ impl Crease { + Fn( MultiBufferRow, bool, - Arc, - &mut WindowContext, + Arc, + &mut Window, + &mut App, ) -> ToggleElement + 'static, ToggleElement: IntoElement, RenderTrailer: 'static + Send + Sync - + Fn(MultiBufferRow, bool, &mut WindowContext) -> TrailerElement + + Fn(MultiBufferRow, bool, &mut Window, &mut App) -> TrailerElement + 'static, TrailerElement: IntoElement, { Crease::Inline { range, placeholder, - render_toggle: Some(Arc::new(move |row, folded, toggle, cx| { - render_toggle(row, folded, toggle, cx).into_any_element() + render_toggle: Some(Arc::new(move |row, folded, toggle, window, cx| { + render_toggle(row, folded, toggle, window, cx).into_any_element() })), - render_trailer: Some(Arc::new(move |row, folded, cx| { - render_trailer(row, folded, cx).into_any_element() + render_trailer: Some(Arc::new(move |row, folded, window, cx| { + render_trailer(row, folded, window, cx).into_any_element() })), metadata: None, } @@ -387,11 +389,11 @@ impl SeekTarget<'_, ItemSummary, ItemSummary> for Anchor { #[cfg(test)] mod test { use super::*; - use gpui::{div, AppContext}; + use gpui::{div, App}; use multi_buffer::MultiBuffer; #[gpui::test] - fn test_insert_and_remove_creases(cx: &mut AppContext) { + fn test_insert_and_remove_creases(cx: &mut App) { let text = "line1\nline2\nline3\nline4\nline5"; let buffer = MultiBuffer::build_simple(text, cx); let snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx)); @@ -402,14 +404,14 @@ mod test { Crease::inline( snapshot.anchor_before(Point::new(1, 0))..snapshot.anchor_after(Point::new(1, 5)), FoldPlaceholder::test(), - |_row, _folded, _toggle, _cx| div(), - |_row, _folded, _cx| div(), + |_row, _folded, _toggle, _window, _cx| div(), + |_row, _folded, _window, _cx| div(), ), Crease::inline( snapshot.anchor_before(Point::new(3, 0))..snapshot.anchor_after(Point::new(3, 5)), FoldPlaceholder::test(), - |_row, _folded, _toggle, _cx| div(), - |_row, _folded, _cx| div(), + |_row, _folded, _toggle, _window, _cx| div(), + |_row, _folded, _window, _cx| div(), ), ]; let crease_ids = crease_map.insert(creases, &snapshot); @@ -438,7 +440,7 @@ mod test { } #[gpui::test] - fn test_creases_in_range(cx: &mut AppContext) { + fn test_creases_in_range(cx: &mut App) { let text = "line1\nline2\nline3\nline4\nline5\nline6\nline7"; let buffer = MultiBuffer::build_simple(text, cx); let snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx)); @@ -448,20 +450,20 @@ mod test { Crease::inline( snapshot.anchor_before(Point::new(1, 0))..snapshot.anchor_after(Point::new(1, 5)), FoldPlaceholder::test(), - |_row, _folded, _toggle, _cx| div(), - |_row, _folded, _cx| div(), + |_row, _folded, _toggle, _window, _cx| div(), + |_row, _folded, _window, _cx| div(), ), Crease::inline( snapshot.anchor_before(Point::new(3, 0))..snapshot.anchor_after(Point::new(3, 5)), FoldPlaceholder::test(), - |_row, _folded, _toggle, _cx| div(), - |_row, _folded, _cx| div(), + |_row, _folded, _toggle, _window, _cx| div(), + |_row, _folded, _window, _cx| div(), ), Crease::inline( snapshot.anchor_before(Point::new(5, 0))..snapshot.anchor_after(Point::new(5, 5)), FoldPlaceholder::test(), - |_row, _folded, _toggle, _cx| div(), - |_row, _folded, _cx| div(), + |_row, _folded, _toggle, _window, _cx| div(), + |_row, _folded, _window, _cx| div(), ), ]; crease_map.insert(creases, &snapshot); diff --git a/crates/editor/src/display_map/fold_map.rs b/crates/editor/src/display_map/fold_map.rs index 1f3b985d1f..6ec334c975 100644 --- a/crates/editor/src/display_map/fold_map.rs +++ b/crates/editor/src/display_map/fold_map.rs @@ -2,7 +2,7 @@ use super::{ inlay_map::{InlayBufferRows, InlayChunks, InlayEdit, InlayOffset, InlayPoint, InlaySnapshot}, Highlights, }; -use gpui::{AnyElement, ElementId, WindowContext}; +use gpui::{AnyElement, App, ElementId, Window}; use language::{Chunk, ChunkRenderer, Edit, Point, TextSummary}; use multi_buffer::{ Anchor, AnchorRangeExt, MultiBufferRow, MultiBufferSnapshot, RowInfo, ToOffset, @@ -21,7 +21,8 @@ use util::post_inc; #[derive(Clone)] pub struct FoldPlaceholder { /// Creates an element to represent this fold's placeholder. - pub render: Arc, &mut WindowContext) -> AnyElement>, + pub render: + Arc, &mut Window, &mut App) -> AnyElement>, /// If true, the element is constrained to the shaped width of an ellipsis. pub constrain_width: bool, /// If true, merges the fold with an adjacent one. @@ -33,7 +34,7 @@ pub struct FoldPlaceholder { impl Default for FoldPlaceholder { fn default() -> Self { Self { - render: Arc::new(|_, _, _| gpui::Empty.into_any_element()), + render: Arc::new(|_, _, _, _| gpui::Empty.into_any_element()), constrain_width: true, merge_adjacent: true, type_tag: None, @@ -45,7 +46,7 @@ impl FoldPlaceholder { #[cfg(any(test, feature = "test-support"))] pub fn test() -> Self { Self { - render: Arc::new(|_id, _range, _cx| gpui::Empty.into_any_element()), + render: Arc::new(|_id, _range, _window, _cx| gpui::Empty.into_any_element()), constrain_width: true, merge_adjacent: true, type_tag: None, @@ -485,7 +486,8 @@ impl FoldMap { (fold.placeholder.render)( fold_id, fold.range.0.clone(), - cx, + cx.window, + cx.context, ) }), constrain_width: fold.placeholder.constrain_width, @@ -1395,7 +1397,7 @@ mod tests { use Bias::{Left, Right}; #[gpui::test] - fn test_basic_folds(cx: &mut gpui::AppContext) { + fn test_basic_folds(cx: &mut gpui::App) { init_test(cx); let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx); let subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); @@ -1474,7 +1476,7 @@ mod tests { } #[gpui::test] - fn test_adjacent_folds(cx: &mut gpui::AppContext) { + fn test_adjacent_folds(cx: &mut gpui::App) { init_test(cx); let buffer = MultiBuffer::build_simple("abcdefghijkl", cx); let subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); @@ -1533,7 +1535,7 @@ mod tests { } #[gpui::test] - fn test_overlapping_folds(cx: &mut gpui::AppContext) { + fn test_overlapping_folds(cx: &mut gpui::App) { let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx); let buffer_snapshot = buffer.read(cx).snapshot(cx); let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot); @@ -1550,7 +1552,7 @@ mod tests { } #[gpui::test] - fn test_merging_folds_via_edit(cx: &mut gpui::AppContext) { + fn test_merging_folds_via_edit(cx: &mut gpui::App) { init_test(cx); let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx); let subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); @@ -1577,7 +1579,7 @@ mod tests { } #[gpui::test] - fn test_folds_in_range(cx: &mut gpui::AppContext) { + fn test_folds_in_range(cx: &mut gpui::App) { let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx); let buffer_snapshot = buffer.read(cx).snapshot(cx); let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone()); @@ -1608,7 +1610,7 @@ mod tests { } #[gpui::test(iterations = 100)] - fn test_random_folds(cx: &mut gpui::AppContext, mut rng: StdRng) { + fn test_random_folds(cx: &mut gpui::App, mut rng: StdRng) { init_test(cx); let operations = env::var("OPERATIONS") .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) @@ -1879,7 +1881,7 @@ mod tests { } #[gpui::test] - fn test_buffer_rows(cx: &mut gpui::AppContext) { + fn test_buffer_rows(cx: &mut gpui::App) { let text = sample_text(6, 6, 'a') + "\n"; let buffer = MultiBuffer::build_simple(&text, cx); @@ -1911,7 +1913,7 @@ mod tests { ); } - fn init_test(cx: &mut gpui::AppContext) { + fn init_test(cx: &mut gpui::App) { let store = SettingsStore::test(cx); cx.set_global(store); } diff --git a/crates/editor/src/display_map/inlay_map.rs b/crates/editor/src/display_map/inlay_map.rs index 9fba4aec25..02b0d21ef6 100644 --- a/crates/editor/src/display_map/inlay_map.rs +++ b/crates/editor/src/display_map/inlay_map.rs @@ -1070,7 +1070,7 @@ mod tests { hover_links::InlayHighlight, InlayId, MultiBuffer, }; - use gpui::{AppContext, HighlightStyle}; + use gpui::{App, HighlightStyle}; use project::{InlayHint, InlayHintLabel, ResolveState}; use rand::prelude::*; use settings::SettingsStore; @@ -1163,7 +1163,7 @@ mod tests { } #[gpui::test] - fn test_basic_inlays(cx: &mut AppContext) { + fn test_basic_inlays(cx: &mut App) { let buffer = MultiBuffer::build_simple("abcdefghi", cx); let buffer_edits = buffer.update(cx, |buffer, _| buffer.subscribe()); let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx)); @@ -1451,7 +1451,7 @@ mod tests { } #[gpui::test] - fn test_inlay_buffer_rows(cx: &mut AppContext) { + fn test_inlay_buffer_rows(cx: &mut App) { let buffer = MultiBuffer::build_simple("abc\ndef\nghi", cx); let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx)); assert_eq!(inlay_snapshot.text(), "abc\ndef\nghi"); @@ -1488,7 +1488,7 @@ mod tests { } #[gpui::test(iterations = 100)] - fn test_random_inlays(cx: &mut AppContext, mut rng: StdRng) { + fn test_random_inlays(cx: &mut App, mut rng: StdRng) { init_test(cx); let operations = env::var("OPERATIONS") @@ -1792,7 +1792,7 @@ mod tests { } } - fn init_test(cx: &mut AppContext) { + fn init_test(cx: &mut App) { let store = SettingsStore::test(cx); cx.set_global(store); theme::init(theme::LoadThemes::JustBase, cx); diff --git a/crates/editor/src/display_map/tab_map.rs b/crates/editor/src/display_map/tab_map.rs index 69ba4ba8a7..824f848aed 100644 --- a/crates/editor/src/display_map/tab_map.rs +++ b/crates/editor/src/display_map/tab_map.rs @@ -608,7 +608,7 @@ mod tests { use rand::{prelude::StdRng, Rng}; #[gpui::test] - fn test_expand_tabs(cx: &mut gpui::AppContext) { + fn test_expand_tabs(cx: &mut gpui::App) { let buffer = MultiBuffer::build_simple("", cx); let buffer_snapshot = buffer.read(cx).snapshot(cx); let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone()); @@ -621,7 +621,7 @@ mod tests { } #[gpui::test] - fn test_long_lines(cx: &mut gpui::AppContext) { + fn test_long_lines(cx: &mut gpui::App) { 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"; @@ -669,7 +669,7 @@ mod tests { } #[gpui::test] - fn test_long_lines_with_character_spanning_max_expansion_column(cx: &mut gpui::AppContext) { + fn test_long_lines_with_character_spanning_max_expansion_column(cx: &mut gpui::App) { let max_expansion_column = 8; let input = "abcdefg⋯hij"; @@ -684,7 +684,7 @@ mod tests { } #[gpui::test] - fn test_marking_tabs(cx: &mut gpui::AppContext) { + fn test_marking_tabs(cx: &mut gpui::App) { let input = "\t \thello"; let buffer = MultiBuffer::build_simple(input, cx); @@ -735,7 +735,7 @@ mod tests { } #[gpui::test(iterations = 100)] - fn test_random_tabs(cx: &mut gpui::AppContext, mut rng: StdRng) { + fn test_random_tabs(cx: &mut gpui::App, 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() { diff --git a/crates/editor/src/display_map/wrap_map.rs b/crates/editor/src/display_map/wrap_map.rs index 30f59be767..c1510cd231 100644 --- a/crates/editor/src/display_map/wrap_map.rs +++ b/crates/editor/src/display_map/wrap_map.rs @@ -3,7 +3,7 @@ use super::{ tab_map::{self, TabEdit, TabPoint, TabSnapshot}, Highlights, }; -use gpui::{AppContext, Context, Font, LineWrapper, Model, ModelContext, Pixels, Task}; +use gpui::{App, AppContext as _, Context, Entity, Font, LineWrapper, Pixels, Task}; use language::{Chunk, Point}; use multi_buffer::{MultiBufferSnapshot, RowInfo}; use smol::future::yield_now; @@ -90,9 +90,9 @@ impl WrapMap { font: Font, font_size: Pixels, wrap_width: Option, - cx: &mut AppContext, - ) -> (Model, WrapSnapshot) { - let handle = cx.new_model(|cx| { + cx: &mut App, + ) -> (Entity, WrapSnapshot) { + let handle = cx.new(|cx| { let mut this = Self { font_with_size: (font, font_size), wrap_width: None, @@ -119,7 +119,7 @@ impl WrapMap { &mut self, tab_snapshot: TabSnapshot, edits: Vec, - cx: &mut ModelContext, + cx: &mut Context, ) -> (WrapSnapshot, Patch) { if self.wrap_width.is_some() { self.pending_edits.push_back((tab_snapshot, edits)); @@ -138,7 +138,7 @@ impl WrapMap { &mut self, font: Font, font_size: Pixels, - cx: &mut ModelContext, + cx: &mut Context, ) -> bool { let font_with_size = (font, font_size); @@ -151,11 +151,7 @@ impl WrapMap { } } - pub fn set_wrap_width( - &mut self, - wrap_width: Option, - cx: &mut ModelContext, - ) -> bool { + pub fn set_wrap_width(&mut self, wrap_width: Option, cx: &mut Context) -> bool { if wrap_width == self.wrap_width { return false; } @@ -165,7 +161,7 @@ impl WrapMap { true } - fn rewrap(&mut self, cx: &mut ModelContext) { + fn rewrap(&mut self, cx: &mut Context) { self.background_task.take(); self.interpolated_edits.clear(); self.pending_edits.clear(); @@ -236,7 +232,7 @@ impl WrapMap { } } - fn flush_edits(&mut self, cx: &mut ModelContext) { + fn flush_edits(&mut self, cx: &mut Context) { if !self.snapshot.interpolated { let mut to_remove_len = 0; for (tab_snapshot, _) in &self.pending_edits { diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 34dd5ca299..875f05599c 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -77,14 +77,13 @@ use code_context_menus::{ }; use git::blame::GitBlame; use gpui::{ - div, impl_actions, point, prelude::*, px, relative, size, Action, AnyElement, AppContext, + div, impl_actions, point, prelude::*, px, relative, size, Action, AnyElement, App, AsyncWindowContext, AvailableSpace, Bounds, ClipboardEntry, ClipboardItem, Context, - DispatchPhase, ElementId, EventEmitter, FocusHandle, FocusOutEvent, FocusableView, FontId, - FontWeight, Global, HighlightStyle, Hsla, InteractiveText, KeyContext, Model, ModelContext, - MouseButton, PaintQuad, ParentElement, Pixels, Render, SharedString, Size, Styled, StyledText, - Subscription, Task, TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, - UniformListScrollHandle, View, ViewContext, ViewInputHandler, VisualContext, WeakFocusHandle, - WeakView, WindowContext, + DispatchPhase, ElementId, Entity, EventEmitter, FocusHandle, FocusOutEvent, Focusable, FontId, + FontWeight, Global, HighlightStyle, Hsla, InteractiveText, KeyContext, MouseButton, PaintQuad, + ParentElement, Pixels, Render, SharedString, Size, Styled, StyledText, Subscription, Task, + TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, + ViewInputHandler, WeakEntity, WeakFocusHandle, Window, }; use highlight_matching_bracket::refresh_matching_bracket_highlights; use hover_popover::{hide_hover, HoverState}; @@ -194,8 +193,8 @@ pub fn render_parsed_markdown( element_id: impl Into, parsed: &language::ParsedMarkdown, editor_style: &EditorStyle, - workspace: Option>, - cx: &mut WindowContext, + workspace: Option>, + cx: &mut App, ) -> InteractiveText { let code_span_background_color = cx .theme() @@ -239,18 +238,21 @@ pub fn render_parsed_markdown( element_id, StyledText::new(parsed.text.clone()).with_highlights(&editor_style.text, highlights), ) - .on_click(link_ranges, move |clicked_range_ix, cx| { - match &links[clicked_range_ix] { + .on_click( + link_ranges, + move |clicked_range_ix, window, cx| match &links[clicked_range_ix] { markdown::Link::Web { url } => cx.open_url(url), markdown::Link::Path { path } => { if let Some(workspace) = &workspace { _ = workspace.update(cx, |workspace, cx| { - workspace.open_abs_path(path.clone(), false, cx).detach(); + workspace + .open_abs_path(path.clone(), false, window, cx) + .detach(); }); } } - } - }) + }, + ) } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -288,19 +290,19 @@ impl Navigated { } } -pub fn init_settings(cx: &mut AppContext) { +pub fn init_settings(cx: &mut App) { EditorSettings::register(cx); } -pub fn init(cx: &mut AppContext) { +pub fn init(cx: &mut App) { init_settings(cx); workspace::register_project_item::(cx); workspace::FollowableViewRegistry::register::(cx); workspace::register_serializable_item::(cx); - cx.observe_new_views( - |workspace: &mut Workspace, _cx: &mut ViewContext| { + cx.observe_new( + |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context| { workspace.register_action(Editor::new_file); workspace.register_action(Editor::new_file_vertical); workspace.register_action(Editor::new_file_horizontal); @@ -311,18 +313,28 @@ pub fn init(cx: &mut AppContext) { cx.on_action(move |_: &workspace::NewFile, cx| { let app_state = workspace::AppState::global(cx); if let Some(app_state) = app_state.upgrade() { - workspace::open_new(Default::default(), app_state, cx, |workspace, cx| { - Editor::new_file(workspace, &Default::default(), cx) - }) + workspace::open_new( + Default::default(), + app_state, + cx, + |workspace, window, cx| { + Editor::new_file(workspace, &Default::default(), window, cx) + }, + ) .detach(); } }); cx.on_action(move |_: &workspace::NewWindow, cx| { let app_state = workspace::AppState::global(cx); if let Some(app_state) = app_state.upgrade() { - workspace::open_new(Default::default(), app_state, cx, |workspace, cx| { - Editor::new_file(workspace, &Default::default(), cx) - }) + workspace::open_new( + Default::default(), + app_state, + cx, + |workspace, window, cx| { + Editor::new_file(workspace, &Default::default(), window, cx) + }, + ) .detach(); } }); @@ -426,7 +438,7 @@ impl Default for EditorStyle { } } -pub fn make_inlay_hints_style(cx: &WindowContext) -> HighlightStyle { +pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle { let show_background = language_settings::language_settings(None, None, cx) .inlay_hints .show_background; @@ -438,7 +450,7 @@ pub fn make_inlay_hints_style(cx: &WindowContext) -> HighlightStyle { } } -pub fn make_suggestion_styles(cx: &WindowContext) -> InlineCompletionStyles { +pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles { InlineCompletionStyles { insertion: HighlightStyle { color: Some(cx.theme().status().predictive), @@ -525,7 +537,7 @@ impl EditorActionId { // type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option; type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range]>); -type GutterHighlight = (fn(&AppContext) -> Hsla, Arc<[Range]>); +type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range]>); #[derive(Default)] struct ScrollbarMarkerState { @@ -578,7 +590,7 @@ struct BufferOffset(usize); // Addons allow storing per-editor state in other crates (e.g. Vim) pub trait Addon: 'static { - fn extend_key_context(&self, _: &mut KeyContext, _: &AppContext) {} + fn extend_key_context(&self, _: &mut KeyContext, _: &App) {} fn to_any(&self) -> &dyn std::any::Any; } @@ -589,17 +601,17 @@ pub enum IsVimMode { No, } -/// Zed's primary text input `View`, allowing users to edit a [`MultiBuffer`] +/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`]. /// /// See the [module level documentation](self) for more information. pub struct Editor { focus_handle: FocusHandle, last_focused_descendant: Option, /// The text buffer being edited - buffer: Model, + buffer: Entity, /// Map of how text in the buffer should be displayed. /// Handles soft wraps, folds, fake inlay text insertions, etc. - pub display_map: Model, + pub display_map: Entity, pub selections: SelectionsCollection, pub scroll_manager: ScrollManager, /// When inline assist editors are linked, they all render cursors because @@ -617,11 +629,11 @@ pub struct Editor { active_diagnostics: Option, soft_wrap_mode_override: Option, - project: Option>, + project: Option>, semantics_provider: Option>, completion_provider: Option>, collaboration_hub: Option>, - blink_manager: Model, + blink_manager: Entity, show_cursor_names: bool, hovered_cursors: HashMap>, pub show_local_selections: bool, @@ -662,7 +674,7 @@ pub struct Editor { current_line_highlight: Option, collapse_matches: bool, autoindent_mode: Option, - workspace: Option<(WeakView, Option)>, + workspace: Option<(WeakEntity, Option)>, input_enabled: bool, use_modal_editing: bool, read_only: bool, @@ -687,7 +699,8 @@ pub struct Editor { style: Option, text_style_refinement: Option, next_editor_action_id: EditorActionId, - editor_actions: Rc)>>>>, + editor_actions: + Rc)>>>>, use_autoclose: bool, use_auto_surround: bool, auto_replace_emoji_shortcode: bool, @@ -697,12 +710,17 @@ pub struct Editor { git_blame_inline_enabled: bool, serialize_dirty_buffers: bool, show_selection_menu: Option, - blame: Option>, + blame: Option>, blame_subscription: Option, custom_context_menu: Option< Box< dyn 'static - + Fn(&mut Self, DisplayPoint, &mut ViewContext) -> Option>, + + Fn( + &mut Self, + DisplayPoint, + &mut Window, + &mut Context, + ) -> Option>, >, >, last_bounds: Option>, @@ -941,7 +959,7 @@ struct SnippetState { pub struct RenameState { pub range: Range, pub old_name: Arc, - pub editor: View, + pub editor: Entity, block_id: CustomBlockId, } @@ -1037,73 +1055,86 @@ pub enum MultibufferSelectionMode { } impl Editor { - pub fn single_line(cx: &mut ViewContext) -> Self { - let buffer = cx.new_model(|cx| Buffer::local("", cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + pub fn single_line(window: &mut Window, cx: &mut Context) -> Self { + let buffer = cx.new(|cx| Buffer::local("", cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); Self::new( EditorMode::SingleLine { auto_width: false }, buffer, None, false, + window, cx, ) } - pub fn multi_line(cx: &mut ViewContext) -> Self { - let buffer = cx.new_model(|cx| Buffer::local("", cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); - Self::new(EditorMode::Full, buffer, None, false, cx) + pub fn multi_line(window: &mut Window, cx: &mut Context) -> Self { + let buffer = cx.new(|cx| Buffer::local("", cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); + Self::new(EditorMode::Full, buffer, None, false, window, cx) } - pub fn auto_width(cx: &mut ViewContext) -> Self { - let buffer = cx.new_model(|cx| Buffer::local("", cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + pub fn auto_width(window: &mut Window, cx: &mut Context) -> Self { + let buffer = cx.new(|cx| Buffer::local("", cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); Self::new( EditorMode::SingleLine { auto_width: true }, buffer, None, false, + window, cx, ) } - pub fn auto_height(max_lines: usize, cx: &mut ViewContext) -> Self { - let buffer = cx.new_model(|cx| Buffer::local("", cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); + pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context) -> Self { + let buffer = cx.new(|cx| Buffer::local("", cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); Self::new( EditorMode::AutoHeight { max_lines }, buffer, None, false, + window, cx, ) } pub fn for_buffer( - buffer: Model, - project: Option>, - cx: &mut ViewContext, + buffer: Entity, + project: Option>, + window: &mut Window, + cx: &mut Context, ) -> Self { - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); - Self::new(EditorMode::Full, buffer, project, false, cx) + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); + Self::new(EditorMode::Full, buffer, project, false, window, cx) } pub fn for_multibuffer( - buffer: Model, - project: Option>, + buffer: Entity, + project: Option>, show_excerpt_controls: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Self { - Self::new(EditorMode::Full, buffer, project, show_excerpt_controls, cx) + Self::new( + EditorMode::Full, + buffer, + project, + show_excerpt_controls, + window, + cx, + ) } - pub fn clone(&self, cx: &mut ViewContext) -> Self { + pub fn clone(&self, window: &mut Window, cx: &mut Context) -> Self { let show_excerpt_controls = self.display_map.read(cx).show_excerpt_controls(); let mut clone = Self::new( self.mode, self.buffer.clone(), self.project.clone(), show_excerpt_controls, + window, cx, ); self.display_map.update(cx, |display_map, cx| { @@ -1120,17 +1151,18 @@ impl Editor { pub fn new( mode: EditorMode, - buffer: Model, - project: Option>, + buffer: Entity, + project: Option>, show_excerpt_controls: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Self { - let style = cx.text_style(); - let font_size = style.font_size.to_pixels(cx.rem_size()); - let editor = cx.view().downgrade(); + let style = window.text_style(); + let font_size = style.font_size.to_pixels(window.rem_size()); + let editor = cx.model().downgrade(); let fold_placeholder = FoldPlaceholder { constrain_width: true, - render: Arc::new(move |fold_id, fold_range, cx| { + render: Arc::new(move |fold_id, fold_range, _, cx| { let editor = editor.clone(); div() .id(fold_id) @@ -1141,8 +1173,8 @@ impl Editor { .size_full() .cursor_pointer() .child("⋯") - .on_mouse_down(MouseButton::Left, |_, cx| cx.stop_propagation()) - .on_click(move |_, cx| { + .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation()) + .on_click(move |_, _window, cx| { editor .update(cx, |editor, cx| { editor.unfold_ranges( @@ -1160,7 +1192,7 @@ impl Editor { merge_adjacent: true, ..Default::default() }; - let display_map = cx.new_model(|cx| { + let display_map = cx.new(|cx| { DisplayMap::new( buffer.clone(), style.font(), @@ -1177,7 +1209,7 @@ impl Editor { let selections = SelectionsCollection::new(display_map.clone(), buffer.clone()); - let blink_manager = cx.new_model(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx)); + let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx)); let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. }) .then(|| language_settings::SoftWrap::None); @@ -1186,29 +1218,39 @@ impl Editor { if mode == EditorMode::Full { if let Some(project) = project.as_ref() { if buffer.read(cx).is_singleton() { - project_subscriptions.push(cx.observe(project, |_, _, cx| { + project_subscriptions.push(cx.observe_in(project, window, |_, _, _, cx| { cx.emit(EditorEvent::TitleChanged); })); } - project_subscriptions.push(cx.subscribe(project, |editor, _, event, cx| { - if let project::Event::RefreshInlayHints = event { - editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx); - } else if let project::Event::SnippetEdit(id, snippet_edits) = event { - if let Some(buffer) = editor.buffer.read(cx).buffer(*id) { - let focus_handle = editor.focus_handle(cx); - if focus_handle.is_focused(cx) { - let snapshot = buffer.read(cx).snapshot(); - for (range, snippet) in snippet_edits { - let editor_range = - language::range_from_lsp(*range).to_offset(&snapshot); - editor - .insert_snippet(&[editor_range], snippet.clone(), cx) - .ok(); + project_subscriptions.push(cx.subscribe_in( + project, + window, + |editor, _, event, window, cx| { + if let project::Event::RefreshInlayHints = event { + editor + .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx); + } else if let project::Event::SnippetEdit(id, snippet_edits) = event { + if let Some(buffer) = editor.buffer.read(cx).buffer(*id) { + let focus_handle = editor.focus_handle(cx); + if focus_handle.is_focused(window) { + let snapshot = buffer.read(cx).snapshot(); + for (range, snippet) in snippet_edits { + let editor_range = + language::range_from_lsp(*range).to_offset(&snapshot); + editor + .insert_snippet( + &[editor_range], + snippet.clone(), + window, + cx, + ) + .ok(); + } } } } - } - })); + }, + )); if let Some(task_inventory) = project .read(cx) .task_store() @@ -1216,9 +1258,13 @@ impl Editor { .task_inventory() .cloned() { - project_subscriptions.push(cx.observe(&task_inventory, |editor, _, cx| { - editor.tasks_update_task = Some(editor.refresh_runnables(cx)); - })); + project_subscriptions.push(cx.observe_in( + &task_inventory, + window, + |editor, _, window, cx| { + editor.tasks_update_task = Some(editor.refresh_runnables(window, cx)); + }, + )); } } } @@ -1228,12 +1274,14 @@ impl Editor { let inlay_hint_settings = inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx); let focus_handle = cx.focus_handle(); - cx.on_focus(&focus_handle, Self::handle_focus).detach(); - cx.on_focus_in(&focus_handle, Self::handle_focus_in) + cx.on_focus(&focus_handle, window, Self::handle_focus) .detach(); - cx.on_focus_out(&focus_handle, Self::handle_focus_out) + cx.on_focus_in(&focus_handle, window, Self::handle_focus_in) + .detach(); + cx.on_focus_out(&focus_handle, window, Self::handle_focus_out) + .detach(); + cx.on_blur(&focus_handle, window, Self::handle_blur) .detach(); - cx.on_blur(&focus_handle, Self::handle_blur).detach(); let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) { Some(false) @@ -1359,12 +1407,12 @@ impl Editor { tasks: Default::default(), _subscriptions: vec![ cx.observe(&buffer, Self::on_buffer_changed), - cx.subscribe(&buffer, Self::on_buffer_event), - cx.observe(&display_map, Self::on_display_map_changed), + cx.subscribe_in(&buffer, window, Self::on_buffer_event), + cx.observe_in(&display_map, window, Self::on_display_map_changed), cx.observe(&blink_manager, |_, _, cx| cx.notify()), - cx.observe_global::(Self::settings_changed), - cx.observe_window_activation(|editor, cx| { - let active = cx.is_window_active(); + cx.observe_global_in::(window, Self::settings_changed), + cx.observe_window_activation(window, |editor, window, cx| { + let active = window.is_window_active(); editor.blink_manager.update(cx, |blink_manager, cx| { if active { blink_manager.enable(cx); @@ -1387,11 +1435,11 @@ impl Editor { toggle_fold_multiple_buffers: Task::ready(()), text_style_refinement: None, }; - this.tasks_update_task = Some(this.refresh_runnables(cx)); + this.tasks_update_task = Some(this.refresh_runnables(window, cx)); this._subscriptions.extend(project_subscriptions); - this.end_selection(cx); - this.scroll_manager.show_scrollbar(cx); + this.end_selection(window, cx); + this.scroll_manager.show_scrollbar(window, cx); if mode == EditorMode::Full { let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars(); @@ -1399,7 +1447,7 @@ impl Editor { if this.git_blame_inline_enabled { this.git_blame_inline_enabled = true; - this.start_git_blame_inline(false, cx); + this.start_git_blame_inline(false, window, cx); } if let Some(buffer) = buffer.read(cx).as_singleton() { @@ -1418,13 +1466,13 @@ impl Editor { this } - pub fn mouse_menu_is_focused(&self, cx: &WindowContext) -> bool { + pub fn mouse_menu_is_focused(&self, window: &mut Window, cx: &mut App) -> bool { self.mouse_context_menu .as_ref() - .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(cx)) + .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window)) } - fn key_context(&self, cx: &ViewContext) -> KeyContext { + fn key_context(&self, window: &mut Window, cx: &mut Context) -> KeyContext { let mut key_context = KeyContext::new_with_defaults(); key_context.add("Editor"); let mode = match self.mode { @@ -1454,8 +1502,8 @@ impl Editor { } // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused. - if !self.focus_handle(cx).contains_focused(cx) - || (self.is_focused(cx) || self.mouse_menu_is_focused(cx)) + if !self.focus_handle(cx).contains_focused(window, cx) + || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx)) { for addon in self.addons.values() { addon.extend_key_context(&mut key_context, cx) @@ -1486,12 +1534,14 @@ impl Editor { pub fn new_file( workspace: &mut Workspace, _: &workspace::NewFile, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - Self::new_in_workspace(workspace, cx).detach_and_prompt_err( + Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err( "Failed to create buffer", + window, cx, - |e, _| match e.error_code() { + |e, _, _| match e.error_code() { ErrorCode::RemoteUpgradeRequired => Some(format!( "The remote instance of Zed does not support this yet. It must be upgraded to {}", e.error_tag("required").unwrap_or("the latest version") @@ -1503,17 +1553,18 @@ impl Editor { pub fn new_in_workspace( workspace: &mut Workspace, - cx: &mut ViewContext, - ) -> Task>> { + window: &mut Window, + cx: &mut Context, + ) -> Task>> { let project = workspace.project().clone(); let create = project.update(cx, |project, cx| project.create_buffer(cx)); - cx.spawn(|workspace, mut cx| async move { + cx.spawn_in(window, |workspace, mut cx| async move { let buffer = create.await?; - workspace.update(&mut cx, |workspace, cx| { + workspace.update_in(&mut cx, |workspace, window, cx| { let editor = - cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx)); - workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, cx); + cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)); + workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx); editor }) }) @@ -1522,46 +1573,52 @@ impl Editor { fn new_file_vertical( workspace: &mut Workspace, _: &workspace::NewFileSplitVertical, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), cx) + Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx) } fn new_file_horizontal( workspace: &mut Workspace, _: &workspace::NewFileSplitHorizontal, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), cx) + Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx) } fn new_file_in_direction( workspace: &mut Workspace, direction: SplitDirection, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let project = workspace.project().clone(); let create = project.update(cx, |project, cx| project.create_buffer(cx)); - cx.spawn(|workspace, mut cx| async move { + cx.spawn_in(window, |workspace, mut cx| async move { let buffer = create.await?; - workspace.update(&mut cx, move |workspace, cx| { + workspace.update_in(&mut cx, move |workspace, window, cx| { workspace.split_item( direction, Box::new( - cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx)), + cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)), ), + window, cx, ) })?; anyhow::Ok(()) }) - .detach_and_prompt_err("Failed to create buffer", cx, |e, _| match e.error_code() { - ErrorCode::RemoteUpgradeRequired => Some(format!( + .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| { + match e.error_code() { + ErrorCode::RemoteUpgradeRequired => Some(format!( "The remote instance of Zed does not support this yet. It must be upgraded to {}", e.error_tag("required").unwrap_or("the latest version") )), - _ => None, + _ => None, + } }); } @@ -1569,19 +1626,19 @@ impl Editor { self.leader_peer_id } - pub fn buffer(&self) -> &Model { + pub fn buffer(&self) -> &Entity { &self.buffer } - pub fn workspace(&self) -> Option> { + pub fn workspace(&self) -> Option> { self.workspace.as_ref()?.0.upgrade() } - pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> { + pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> { self.buffer().read(cx).title(cx) } - pub fn snapshot(&self, cx: &mut WindowContext) -> EditorSnapshot { + pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot { let git_blame_gutter_max_author_length = self .render_git_blame_gutter(cx) .then(|| { @@ -1607,7 +1664,7 @@ impl Editor { scroll_anchor: self.scroll_manager.anchor(), ongoing_scroll: self.scroll_manager.ongoing_scroll(), placeholder_text: self.placeholder_text.clone(), - is_focused: self.focus_handle.is_focused(cx), + is_focused: self.focus_handle.is_focused(window), current_line_highlight: self .current_line_highlight .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight), @@ -1615,22 +1672,18 @@ impl Editor { } } - pub fn language_at(&self, point: T, cx: &AppContext) -> Option> { + pub fn language_at(&self, point: T, cx: &App) -> Option> { self.buffer.read(cx).language_at(point, cx) } - pub fn file_at( - &self, - point: T, - cx: &AppContext, - ) -> Option> { + pub fn file_at(&self, point: T, cx: &App) -> Option> { self.buffer.read(cx).read(cx).file_at(point).cloned() } pub fn active_excerpt( &self, - cx: &AppContext, - ) -> Option<(ExcerptId, Model, Range)> { + cx: &App, + ) -> Option<(ExcerptId, Entity, Range)> { self.buffer .read(cx) .excerpt_containing(self.selections.newest_anchor().head(), cx) @@ -1651,7 +1704,12 @@ impl Editor { pub fn set_custom_context_menu( &mut self, f: impl 'static - + Fn(&mut Self, DisplayPoint, &mut ViewContext) -> Option>, + + Fn( + &mut Self, + DisplayPoint, + &mut Window, + &mut Context, + ) -> Option>, ) { self.custom_context_menu = Some(Box::new(f)) } @@ -1670,31 +1728,32 @@ impl Editor { pub fn set_inline_completion_provider( &mut self, - provider: Option>, - cx: &mut ViewContext, + provider: Option>, + window: &mut Window, + cx: &mut Context, ) where T: InlineCompletionProvider, { self.inline_completion_provider = provider.map(|provider| RegisteredInlineCompletionProvider { - _subscription: cx.observe(&provider, |this, _, cx| { - if this.focus_handle.is_focused(cx) { - this.update_visible_inline_completion(cx); + _subscription: cx.observe_in(&provider, window, |this, _, window, cx| { + if this.focus_handle.is_focused(window) { + this.update_visible_inline_completion(window, cx); } }), provider: Arc::new(provider), }); - self.refresh_inline_completion(false, false, cx); + self.refresh_inline_completion(false, false, window, cx); } - pub fn placeholder_text(&self, _cx: &WindowContext) -> Option<&str> { + pub fn placeholder_text(&self) -> Option<&str> { self.placeholder_text.as_deref() } pub fn set_placeholder_text( &mut self, placeholder_text: impl Into>, - cx: &mut ViewContext, + cx: &mut Context, ) { let placeholder_text = Some(placeholder_text.into()); if self.placeholder_text != placeholder_text { @@ -1703,7 +1762,7 @@ impl Editor { } } - pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext) { + pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context) { self.cursor_shape = cursor_shape; // Disrupt blink for immediate user feedback that the cursor shape has changed @@ -1723,7 +1782,7 @@ impl Editor { self.collapse_matches = collapse_matches; } - pub fn register_buffers_with_language_servers(&mut self, cx: &mut ViewContext) { + pub fn register_buffers_with_language_servers(&mut self, cx: &mut Context) { let buffers = self.buffer.read(cx).all_buffers(); let Some(lsp_store) = self.lsp_store(cx) else { return; @@ -1746,7 +1805,7 @@ impl Editor { range.clone() } - pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut ViewContext) { + pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context) { if self.display_map.read(cx).clip_at_line_ends != clip { self.display_map .update(cx, |map, _| map.clip_at_line_ends = clip); @@ -1757,7 +1816,7 @@ impl Editor { self.input_enabled = input_enabled; } - pub fn set_inline_completions_enabled(&mut self, enabled: bool, cx: &mut ViewContext) { + pub fn set_inline_completions_enabled(&mut self, enabled: bool, cx: &mut Context) { self.enable_inline_completions = enabled; if !self.enable_inline_completions { self.take_active_inline_completion(cx); @@ -1777,7 +1836,7 @@ impl Editor { } } - pub fn read_only(&self, cx: &AppContext) -> bool { + pub fn read_only(&self, cx: &App) -> bool { self.read_only || self.buffer.read(cx).read_only() } @@ -1800,10 +1859,11 @@ impl Editor { pub fn toggle_inline_completions( &mut self, _: &ToggleInlineCompletions, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if self.show_inline_completions_override.is_some() { - self.set_show_inline_completions(None, cx); + self.set_show_inline_completions(None, window, cx); } else { let cursor = self.selections.newest_anchor().head(); if let Some((buffer, cursor_buffer_position)) = @@ -1811,7 +1871,7 @@ impl Editor { { let show_inline_completions = !self.should_show_inline_completions(&buffer, cursor_buffer_position, cx); - self.set_show_inline_completions(Some(show_inline_completions), cx); + self.set_show_inline_completions(Some(show_inline_completions), window, cx); } } } @@ -1819,13 +1879,14 @@ impl Editor { pub fn set_show_inline_completions( &mut self, show_inline_completions: Option, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { self.show_inline_completions_override = show_inline_completions; - self.refresh_inline_completion(false, true, cx); + self.refresh_inline_completion(false, true, window, cx); } - pub fn inline_completions_enabled(&self, cx: &AppContext) -> bool { + pub fn inline_completions_enabled(&self, cx: &App) -> bool { let cursor = self.selections.newest_anchor().head(); if let Some((buffer, buffer_position)) = self.buffer.read(cx).text_anchor_for_position(cursor, cx) @@ -1838,9 +1899,9 @@ impl Editor { fn should_show_inline_completions( &self, - buffer: &Model, + buffer: &Entity, buffer_position: language::Anchor, - cx: &AppContext, + cx: &App, ) -> bool { if !self.snippet_stack.is_empty() { return false; @@ -1863,9 +1924,9 @@ impl Editor { fn inline_completions_disabled_in_scope( &self, - buffer: &Model, + buffer: &Entity, buffer_position: language::Anchor, - cx: &AppContext, + cx: &App, ) -> bool { let snapshot = buffer.read(cx).snapshot(); let settings = snapshot.settings_at(buffer_position, cx); @@ -1895,9 +1956,10 @@ impl Editor { local: bool, old_cursor_position: &Anchor, show_completions: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - cx.invalidate_character_coordinates(); + window.invalidate_character_coordinates(); // Copy selections to primary selection buffer #[cfg(any(target_os = "linux", target_os = "freebsd"))] @@ -1922,7 +1984,7 @@ impl Editor { } } - if self.focus_handle.is_focused(cx) && self.leader_peer_id.is_none() { + if self.focus_handle.is_focused(window) && self.leader_peer_id.is_none() { self.buffer.update(cx, |buffer, cx| { buffer.set_active_selections( &self.selections.disjoint_anchors(), @@ -1943,7 +2005,7 @@ impl Editor { self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer); self.snippet_stack .invalidate(&self.selections.disjoint_anchors(), buffer); - self.take_rename(false, cx); + self.take_rename(false, window, cx); let new_cursor_position = self.selections.newest_anchor().head(); @@ -1999,11 +2061,11 @@ impl Editor { .detach(); if show_completions { - self.show_completions(&ShowCompletions { trigger: None }, cx); + self.show_completions(&ShowCompletions { trigger: None }, window, cx); } } else { drop(context_menu); - self.hide_context_menu(cx); + self.hide_context_menu(window, cx); } } else { drop(context_menu); @@ -2016,13 +2078,13 @@ impl Editor { { self.available_code_actions.take(); } - self.refresh_code_actions(cx); + self.refresh_code_actions(window, cx); self.refresh_document_highlights(cx); - refresh_matching_bracket_highlights(self, cx); - self.update_visible_inline_completion(cx); - linked_editing_ranges::refresh_linked_ranges(self, cx); + refresh_matching_bracket_highlights(self, window, cx); + self.update_visible_inline_completion(window, cx); + linked_editing_ranges::refresh_linked_ranges(self, window, cx); if self.git_blame_inline_enabled { - self.start_inline_blame_timer(cx); + self.start_inline_blame_timer(window, cx); } } @@ -2038,17 +2100,19 @@ impl Editor { pub fn change_selections( &mut self, autoscroll: Option, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R, ) -> R { - self.change_selections_inner(autoscroll, true, cx, change) + self.change_selections_inner(autoscroll, true, window, cx, change) } pub fn change_selections_inner( &mut self, autoscroll: Option, request_completions: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R, ) -> R { let old_cursor_position = self.selections.newest_anchor().head(); @@ -2060,14 +2124,14 @@ impl Editor { if let Some(autoscroll) = autoscroll { self.request_autoscroll(autoscroll, cx); } - self.selections_did_change(true, &old_cursor_position, request_completions, cx); + self.selections_did_change(true, &old_cursor_position, request_completions, window, cx); if self.should_open_signature_help_automatically( &old_cursor_position, self.signature_help_state.backspace_pressed(), cx, ) { - self.show_signature_help(&ShowSignatureHelp, cx); + self.show_signature_help(&ShowSignatureHelp, window, cx); } self.signature_help_state.set_backspace_pressed(false); } @@ -2075,7 +2139,7 @@ impl Editor { result } - pub fn edit(&mut self, edits: I, cx: &mut ViewContext) + pub fn edit(&mut self, edits: I, cx: &mut Context) where I: IntoIterator, T)>, S: ToOffset, @@ -2089,7 +2153,7 @@ impl Editor { .update(cx, |buffer, cx| buffer.edit(edits, None, cx)); } - pub fn edit_with_autoindent(&mut self, edits: I, cx: &mut ViewContext) + pub fn edit_with_autoindent(&mut self, edits: I, cx: &mut Context) where I: IntoIterator, T)>, S: ToOffset, @@ -2108,7 +2172,7 @@ impl Editor { &mut self, edits: I, original_indent_columns: Vec, - cx: &mut ViewContext, + cx: &mut Context, ) where I: IntoIterator, T)>, S: ToOffset, @@ -2129,30 +2193,30 @@ impl Editor { }); } - fn select(&mut self, phase: SelectPhase, cx: &mut ViewContext) { - self.hide_context_menu(cx); + fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context) { + self.hide_context_menu(window, cx); match phase { SelectPhase::Begin { position, add, click_count, - } => self.begin_selection(position, add, click_count, cx), + } => self.begin_selection(position, add, click_count, window, cx), SelectPhase::BeginColumnar { position, goal_column, reset, - } => self.begin_columnar_selection(position, goal_column, reset, cx), + } => self.begin_columnar_selection(position, goal_column, reset, window, cx), SelectPhase::Extend { position, click_count, - } => self.extend_selection(position, click_count, cx), + } => self.extend_selection(position, click_count, window, cx), SelectPhase::Update { position, goal_column, scroll_delta, - } => self.update_selection(position, goal_column, scroll_delta, cx), - SelectPhase::End => self.end_selection(cx), + } => self.update_selection(position, goal_column, scroll_delta, window, cx), + SelectPhase::End => self.end_selection(window, cx), } } @@ -2160,11 +2224,12 @@ impl Editor { &mut self, position: DisplayPoint, click_count: usize, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let tail = self.selections.newest::(cx).tail(); - self.begin_selection(position, false, click_count, cx); + self.begin_selection(position, false, click_count, window, cx); let position = position.to_offset(&display_map, Bias::Left); let tail_anchor = display_map.buffer_snapshot.anchor_before(tail); @@ -2186,7 +2251,7 @@ impl Editor { _ => {} } - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.set_pending(pending_selection, pending_mode) }); } @@ -2196,11 +2261,12 @@ impl Editor { position: DisplayPoint, add: bool, click_count: usize, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - if !self.focus_handle.is_focused(cx) { + if !self.focus_handle.is_focused(window) { self.last_focused_descendant = None; - cx.focus(&self.focus_handle); + window.focus(&self.focus_handle); } let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); @@ -2270,7 +2336,7 @@ impl Editor { let selections_count = self.selections.count(); - self.change_selections(auto_scroll.then(Autoscroll::newest), cx, |s| { + self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| { if let Some(point_to_delete) = point_to_delete { s.delete(point_to_delete); @@ -2294,11 +2360,12 @@ impl Editor { position: DisplayPoint, goal_column: u32, reset: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - if !self.focus_handle.is_focused(cx) { + if !self.focus_handle.is_focused(window) { self.last_focused_descendant = None; - cx.focus(&self.focus_handle); + window.focus(&self.focus_handle); } let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); @@ -2308,7 +2375,7 @@ impl Editor { .buffer_snapshot .anchor_before(position.to_point(&display_map)); - self.change_selections(Some(Autoscroll::newest()), cx, |s| { + self.change_selections(Some(Autoscroll::newest()), window, cx, |s| { s.clear_disjoint(); s.set_pending_anchor_range( pointer_position..pointer_position, @@ -2326,6 +2393,7 @@ impl Editor { position, goal_column, &display_map, + window, cx, ); } @@ -2336,13 +2404,14 @@ impl Editor { position: DisplayPoint, goal_column: u32, scroll_delta: gpui::Point, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); if let Some(tail) = self.columnar_selection_tail.as_ref() { let tail = tail.to_display_point(&display_map); - self.select_columns(tail, position, goal_column, &display_map, cx); + self.select_columns(tail, position, goal_column, &display_map, window, cx); } else if let Some(mut pending) = self.selections.pending_anchor() { let buffer = self.buffer.read(cx).snapshot(cx); let head; @@ -2416,7 +2485,7 @@ impl Editor { pending.reversed = false; } - self.change_selections(None, cx, |s| { + self.change_selections(None, window, cx, |s| { s.set_pending(pending, mode); }); } else { @@ -2424,15 +2493,15 @@ impl Editor { return; } - self.apply_scroll_delta(scroll_delta, cx); + self.apply_scroll_delta(scroll_delta, window, cx); cx.notify(); } - fn end_selection(&mut self, cx: &mut ViewContext) { + fn end_selection(&mut self, window: &mut Window, cx: &mut Context) { self.columnar_selection_tail.take(); if self.selections.pending_anchor().is_some() { let selections = self.selections.all::(cx); - self.change_selections(None, cx, |s| { + self.change_selections(None, window, cx, |s| { s.select(selections); s.clear_pending(); }); @@ -2445,7 +2514,8 @@ impl Editor { head: DisplayPoint, goal_column: u32, display_map: &DisplaySnapshot, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let start_row = cmp::min(tail.row(), head.row()); let end_row = cmp::max(tail.row(), head.row()); @@ -2474,7 +2544,7 @@ impl Editor { }) .collect::>(); - self.change_selections(None, cx, |s| { + self.change_selections(None, window, cx, |s| { s.select_ranges(selection_ranges); }); cx.notify(); @@ -2494,19 +2564,19 @@ impl Editor { self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some() } - pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext) { + pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context) { self.selection_mark_mode = false; if self.clear_expanded_diff_hunks(cx) { cx.notify(); return; } - if self.dismiss_menus_and_popups(true, cx) { + if self.dismiss_menus_and_popups(true, window, cx) { return; } if self.mode == EditorMode::Full - && self.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel()) + && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel()) { return; } @@ -2517,9 +2587,10 @@ impl Editor { pub fn dismiss_menus_and_popups( &mut self, should_report_inline_completion_event: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> bool { - if self.take_rename(false, cx).is_some() { + if self.take_rename(false, window, cx).is_some() { return true; } @@ -2531,9 +2602,9 @@ impl Editor { return true; } - if self.hide_context_menu(cx).is_some() { + if self.hide_context_menu(window, cx).is_some() { if self.show_inline_completions_in_menu(cx) && self.has_active_inline_completion() { - self.update_visible_inline_completion(cx); + self.update_visible_inline_completion(window, cx); } return true; } @@ -2561,8 +2632,8 @@ impl Editor { fn linked_editing_ranges_for( &self, selection: Range, - cx: &AppContext, - ) -> Option, Vec>>> { + cx: &App, + ) -> Option, Vec>>> { if self.linked_edit_ranges.is_empty() { return None; } @@ -2615,7 +2686,7 @@ impl Editor { Some(linked_edits) } - pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext) { + pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context) { let text: Arc = text.into(); if self.read_only(cx) { @@ -2853,7 +2924,7 @@ impl Editor { drop(snapshot); - self.transact(cx, |this, cx| { + self.transact(window, cx, |this, window, cx| { this.buffer.update(cx, |buffer, cx| { buffer.edit(edits, this.autoindent_mode.clone(), cx); }); @@ -2916,13 +2987,13 @@ impl Editor { } let had_active_inline_completion = this.has_active_inline_completion(); - this.change_selections_inner(Some(Autoscroll::fit()), false, cx, |s| { + this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| { s.select(new_selections) }); if !bracket_inserted { if let Some(on_type_format_task) = - this.trigger_on_type_formatting(text.to_string(), cx) + this.trigger_on_type_formatting(text.to_string(), window, cx) { on_type_format_task.detach_and_log_err(cx); } @@ -2933,14 +3004,14 @@ impl Editor { && (editor_settings.auto_signature_help || editor_settings.show_signature_help_after_edits) { - this.show_signature_help(&ShowSignatureHelp, cx); + this.show_signature_help(&ShowSignatureHelp, window, cx); } let trigger_in_words = this.show_inline_completions_in_menu(cx) || !had_active_inline_completion; - this.trigger_completion_on_input(&text, trigger_in_words, cx); - linked_editing_ranges::refresh_linked_ranges(this, cx); - this.refresh_inline_completion(true, false, cx); + this.trigger_completion_on_input(&text, trigger_in_words, window, cx); + linked_editing_ranges::refresh_linked_ranges(this, window, cx); + this.refresh_inline_completion(true, false, window, cx); }); } @@ -2991,8 +3062,8 @@ impl Editor { Some(chars.iter().collect()) } - pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext) { - self.transact(cx, |this, cx| { + pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context) { + self.transact(window, cx, |this, window, cx| { let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = { let selections = this.selections.all::(cx); let multi_buffer = this.buffer.read(cx); @@ -3125,12 +3196,14 @@ impl Editor { }) .collect(); - this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections)); - this.refresh_inline_completion(true, false, cx); + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { + s.select(new_selections) + }); + this.refresh_inline_completion(true, false, window, cx); }); } - pub fn newline_above(&mut self, _: &NewlineAbove, cx: &mut ViewContext) { + pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context) { let buffer = self.buffer.read(cx); let snapshot = buffer.snapshot(cx); @@ -3149,10 +3222,10 @@ impl Editor { rows.push(row + rows_inserted as u32); } - self.transact(cx, |editor, cx| { + self.transact(window, cx, |editor, window, cx| { editor.edit(edits, cx); - editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| { let mut index = 0; s.move_cursors_with(|map, _, _| { let row = rows[index]; @@ -3187,7 +3260,7 @@ impl Editor { }); } - pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext) { + pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context) { let buffer = self.buffer.read(cx); let snapshot = buffer.snapshot(cx); @@ -3209,10 +3282,10 @@ impl Editor { rows.push(row + rows_inserted); } - self.transact(cx, |editor, cx| { + self.transact(window, cx, |editor, window, cx| { editor.edit(edits, cx); - editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| { let mut index = 0; s.move_cursors_with(|map, _, _| { let row = rows[index]; @@ -3247,25 +3320,26 @@ impl Editor { }); } - pub fn insert(&mut self, text: &str, cx: &mut ViewContext) { + pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context) { let autoindent = text.is_empty().not().then(|| AutoindentMode::Block { original_indent_columns: Vec::new(), }); - self.insert_with_autoindent_mode(text, autoindent, cx); + self.insert_with_autoindent_mode(text, autoindent, window, cx); } fn insert_with_autoindent_mode( &mut self, text: &str, autoindent_mode: Option, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if self.read_only(cx) { return; } let text: Arc = text.into(); - self.transact(cx, |this, cx| { + self.transact(window, cx, |this, window, cx| { let old_selections = this.selections.all_adjusted(cx); let selection_anchors = this.buffer.update(cx, |buffer, cx| { let anchors = { @@ -3288,9 +3362,11 @@ impl Editor { anchors }); - this.change_selections(Some(Autoscroll::fit()), cx, |s| { + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select_anchors(selection_anchors); - }) + }); + + cx.notify(); }); } @@ -3298,17 +3374,19 @@ impl Editor { &mut self, text: &str, trigger_in_words: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if self.is_completion_trigger(text, trigger_in_words, cx) { self.show_completions( &ShowCompletions { trigger: Some(text.to_owned()).filter(|x| !x.is_empty()), }, + window, cx, ); } else { - self.hide_context_menu(cx); + self.hide_context_menu(window, cx); } } @@ -3316,7 +3394,7 @@ impl Editor { &self, text: &str, trigger_in_words: bool, - cx: &mut ViewContext, + cx: &mut Context, ) -> bool { let position = self.selections.newest_anchor().head(); let multibuffer = self.buffer.read(cx); @@ -3342,7 +3420,7 @@ impl Editor { /// If any empty selections is touching the start of its innermost containing autoclose /// region, expand it to select the brackets. - fn select_autoclose_pair(&mut self, cx: &mut ViewContext) { + fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context) { let selections = self.selections.all::(cx); let buffer = self.buffer.read(cx).read(cx); let new_selections = self @@ -3402,7 +3480,9 @@ impl Editor { .collect(); drop(buffer); - self.change_selections(None, cx, |selections| selections.select(new_selections)); + self.change_selections(None, window, cx, |selections| { + selections.select(new_selections) + }); } /// Iterate the given selections, and for each one, find the smallest surrounding @@ -3477,7 +3557,12 @@ impl Editor { } } - pub fn toggle_inlay_hints(&mut self, _: &ToggleInlayHints, cx: &mut ViewContext) { + pub fn toggle_inlay_hints( + &mut self, + _: &ToggleInlayHints, + _: &mut Window, + cx: &mut Context, + ) { self.refresh_inlay_hints( InlayHintRefreshReason::Toggle(!self.inlay_hint_cache.enabled), cx, @@ -3488,7 +3573,7 @@ impl Editor { self.inlay_hint_cache.enabled } - fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut ViewContext) { + fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context) { if self.semantics_provider.is_none() || self.mode != EditorMode::Full { return; } @@ -3569,7 +3654,7 @@ impl Editor { } } - fn visible_inlay_hints(&self, cx: &ViewContext) -> Vec { + fn visible_inlay_hints(&self, cx: &Context) -> Vec { self.display_map .read(cx) .current_inlays() @@ -3581,8 +3666,8 @@ impl Editor { pub fn excerpts_for_inlay_hints_query( &self, restrict_to_languages: Option<&HashSet>>, - cx: &mut ViewContext, - ) -> HashMap, clock::Global, Range)> { + cx: &mut Context, + ) -> HashMap, clock::Global, Range)> { let Some(project) = self.project.as_ref() else { return HashMap::default(); }; @@ -3632,11 +3717,11 @@ impl Editor { .collect() } - pub fn text_layout_details(&self, cx: &WindowContext) -> TextLayoutDetails { + pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails { TextLayoutDetails { - text_system: cx.text_system().clone(), + text_system: window.text_system().clone(), editor_style: self.style.clone().unwrap(), - rem_size: cx.rem_size(), + rem_size: window.rem_size(), scroll_anchor: self.scroll_manager.anchor(), visible_rows: self.visible_line_count(), vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin, @@ -3647,7 +3732,7 @@ impl Editor { &self, to_remove: Vec, to_insert: Vec, - cx: &mut ViewContext, + cx: &mut Context, ) { self.display_map.update(cx, |display_map, cx| { display_map.splice_inlays(to_remove, to_insert, cx) @@ -3658,7 +3743,8 @@ impl Editor { fn trigger_on_type_formatting( &self, input: String, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Option>> { if input.len() != 1 { return None; @@ -3698,7 +3784,7 @@ impl Editor { cx, ) }); - Some(cx.spawn(|editor, mut cx| async move { + Some(cx.spawn_in(window, |editor, mut cx| async move { if let Some(transaction) = on_type_formatting.await? { if push_to_client_history { buffer @@ -3715,7 +3801,12 @@ impl Editor { })) } - pub fn show_completions(&mut self, options: &ShowCompletions, cx: &mut ViewContext) { + pub fn show_completions( + &mut self, + options: &ShowCompletions, + window: &mut Window, + cx: &mut Context, + ) { if self.pending_rename.is_some() { return; } @@ -3762,11 +3853,12 @@ impl Editor { }), trigger_kind, }; - let completions = provider.completions(&buffer, buffer_position, completion_context, cx); + let completions = + provider.completions(&buffer, buffer_position, completion_context, window, cx); let sort_completions = provider.sort_completions(); let id = post_inc(&mut self.next_completion_id); - let task = cx.spawn(|editor, mut cx| { + let task = cx.spawn_in(window, |editor, mut cx| { async move { editor.update(&mut cx, |this, _| { this.completion_tasks.retain(|(task_id, _)| *task_id >= id); @@ -3790,7 +3882,7 @@ impl Editor { None }; - editor.update(&mut cx, |editor, cx| { + editor.update_in(&mut cx, |editor, window, cx| { match editor.context_menu.borrow().as_ref() { None => {} Some(CodeContextMenu::Completions(prev_menu)) => { @@ -3801,12 +3893,12 @@ impl Editor { _ => return, } - if editor.focus_handle.is_focused(cx) && menu.is_some() { + if editor.focus_handle.is_focused(window) && menu.is_some() { let mut menu = menu.unwrap(); menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx); if editor.show_inline_completions_in_menu(cx) { - if let Some(hint) = editor.inline_completion_menu_hint(cx) { + if let Some(hint) = editor.inline_completion_menu_hint(window, cx) { menu.show_inline_completion_hint(hint); } } else { @@ -3820,12 +3912,12 @@ impl Editor { } else if editor.completion_tasks.len() <= 1 { // If there are no more completion tasks and the last menu was // empty, we should hide it. - let was_hidden = editor.hide_context_menu(cx).is_none(); + let was_hidden = editor.hide_context_menu(window, cx).is_none(); // If it was already hidden and we don't show inline // completions in the menu, we should also show the // inline-completion when available. if was_hidden && editor.show_inline_completions_in_menu(cx) { - editor.update_visible_inline_completion(cx); + editor.update_visible_inline_completion(window, cx); } } })?; @@ -3841,32 +3933,35 @@ impl Editor { pub fn confirm_completion( &mut self, action: &ConfirmCompletion, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Option>> { - self.do_completion(action.item_ix, CompletionIntent::Complete, cx) + self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx) } pub fn compose_completion( &mut self, action: &ComposeCompletion, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Option>> { - self.do_completion(action.item_ix, CompletionIntent::Compose, cx) + self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx) } - fn toggle_zed_predict_tos(&mut self, cx: &mut ViewContext) { + fn toggle_zed_predict_tos(&mut self, window: &mut Window, cx: &mut Context) { let (Some(workspace), Some(project)) = (self.workspace(), self.project.as_ref()) else { return; }; - ZedPredictTos::toggle(workspace, project.read(cx).user_store().clone(), cx); + ZedPredictTos::toggle(workspace, project.read(cx).user_store().clone(), window, cx); } fn do_completion( &mut self, item_ix: Option, intent: CompletionIntent, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Option>> { use language::ToOffset as _; @@ -3882,7 +3977,7 @@ impl Editor { Some(CompletionEntry::InlineCompletionHint(InlineCompletionMenuHint::None)) => { drop(entries); drop(context_menu); - self.context_menu_next(&Default::default(), cx); + self.context_menu_next(&Default::default(), window, cx); return Some(Task::ready(Ok(()))); } Some(CompletionEntry::InlineCompletionHint( @@ -3890,7 +3985,7 @@ impl Editor { )) => { drop(entries); drop(context_menu); - self.toggle_zed_predict_tos(cx); + self.toggle_zed_predict_tos(window, cx); return Some(Task::ready(Ok(()))); } _ => {} @@ -3899,7 +3994,7 @@ impl Editor { } let completions_menu = - if let CodeContextMenu::Completions(menu) = self.hide_context_menu(cx)? { + if let CodeContextMenu::Completions(menu) = self.hide_context_menu(window, cx)? { menu } else { return None; @@ -3909,7 +4004,7 @@ impl Editor { let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?; let mat = match mat { CompletionEntry::InlineCompletionHint(_) => { - self.accept_inline_completion(&AcceptInlineCompletion, cx); + self.accept_inline_completion(&AcceptInlineCompletion, window, cx); cx.stop_propagation(); return Some(Task::ready(Ok(()))); } @@ -4021,7 +4116,7 @@ impl Editor { text: text.into(), }); - self.transact(cx, |this, cx| { + self.transact(window, cx, |this, window, cx| { if let Some(mut snippet) = snippet { snippet.text = text.to_string(); for tabstop in snippet @@ -4033,7 +4128,7 @@ impl Editor { tabstop.end -= common_prefix_len as isize; } - this.insert_snippet(&ranges, snippet, cx).log_err(); + this.insert_snippet(&ranges, snippet, window, cx).log_err(); } else { this.buffer.update(cx, |buffer, cx| { buffer.edit( @@ -4060,15 +4155,15 @@ impl Editor { }) } - this.refresh_inline_completion(true, false, cx); + this.refresh_inline_completion(true, false, window, cx); }); let show_new_completions_on_confirm = completion .confirm .as_ref() - .map_or(false, |confirm| confirm(intent, cx)); + .map_or(false, |confirm| confirm(intent, window, cx)); if show_new_completions_on_confirm { - self.show_completions(&ShowCompletions { trigger: None }, cx); + self.show_completions(&ShowCompletions { trigger: None }, window, cx); } let provider = self.completion_provider.as_ref()?; @@ -4085,7 +4180,7 @@ impl Editor { if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help { // After the code completion is finished, users often want to know what signatures are needed. // so we should automatically call signature_help - self.show_signature_help(&ShowSignatureHelp, cx); + self.show_signature_help(&ShowSignatureHelp, window, cx); } Some(cx.foreground_executor().spawn(async move { @@ -4094,7 +4189,12 @@ impl Editor { })) } - pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext) { + pub fn toggle_code_actions( + &mut self, + action: &ToggleCodeActions, + window: &mut Window, + cx: &mut Context, + ) { let mut context_menu = self.context_menu.borrow_mut(); if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() { if code_actions.deployed_from_indicator == action.deployed_from_indicator { @@ -4109,18 +4209,18 @@ impl Editor { } } drop(context_menu); - let snapshot = self.snapshot(cx); + let snapshot = self.snapshot(window, cx); let deployed_from_indicator = action.deployed_from_indicator; let mut task = self.code_actions_task.take(); let action = action.clone(); - cx.spawn(|editor, mut cx| async move { + cx.spawn_in(window, |editor, mut cx| async move { while let Some(prev_task) = task { prev_task.await.log_err(); task = editor.update(&mut cx, |this, _| this.code_actions_task.take())?; } - let spawned_test_task = editor.update(&mut cx, |editor, cx| { - if editor.focus_handle.is_focused(cx) { + let spawned_test_task = editor.update_in(&mut cx, |editor, window, cx| { + if editor.focus_handle.is_focused(window) { let multibuffer_point = action .deployed_from_indicator .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot)) @@ -4168,7 +4268,7 @@ impl Editor { Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx) }); - Some(cx.spawn(|editor, mut cx| async move { + Some(cx.spawn_in(window, |editor, mut cx| async move { let task_context = match task_context { Some(task_context) => task_context.await, None => None, @@ -4189,7 +4289,7 @@ impl Editor { && code_actions .as_ref() .map_or(true, |actions| actions.is_empty()); - if let Ok(task) = editor.update(&mut cx, |editor, cx| { + if let Ok(task) = editor.update_in(&mut cx, |editor, window, cx| { *editor.context_menu.borrow_mut() = Some(CodeContextMenu::CodeActions(CodeActionsMenu { buffer, @@ -4204,6 +4304,7 @@ impl Editor { if spawn_straight_away { if let Some(task) = editor.confirm_code_action( &ConfirmCodeAction { item_ix: Some(0) }, + window, cx, ) { cx.notify(); @@ -4234,13 +4335,15 @@ impl Editor { pub fn confirm_code_action( &mut self, action: &ConfirmCodeAction, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Option>> { - let actions_menu = if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(cx)? { - menu - } else { - return None; - }; + let actions_menu = + if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? { + menu + } else { + return None; + }; let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item); let action = actions_menu.actions.get(action_ix)?; let title = action.label(); @@ -4267,9 +4370,9 @@ impl Editor { provider, } => { let apply_code_action = - provider.apply_code_action(buffer, action, excerpt_id, true, cx); + provider.apply_code_action(buffer, action, excerpt_id, true, window, cx); let workspace = workspace.downgrade(); - Some(cx.spawn(|editor, cx| async move { + Some(cx.spawn_in(window, |editor, cx| async move { let project_transaction = apply_code_action.await?; Self::open_project_transaction( &editor, @@ -4285,14 +4388,14 @@ impl Editor { } pub async fn open_project_transaction( - this: &WeakView, - workspace: WeakView, + this: &WeakEntity, + workspace: WeakEntity, transaction: ProjectTransaction, title: String, mut cx: AsyncWindowContext, ) -> Result<()> { let mut entries = transaction.0.into_iter().collect::>(); - cx.update(|cx| { + cx.update(|_, cx| { entries.sort_unstable_by_key(|(buffer, _)| { buffer.read(cx).file().map(|f| f.path().clone()) }); @@ -4332,7 +4435,7 @@ impl Editor { } let mut ranges_to_highlight = Vec::new(); - let excerpt_buffer = cx.new_model(|cx| { + let excerpt_buffer = cx.new(|cx| { let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title); for (buffer_handle, transaction) in &entries { let buffer = buffer_handle.read(cx); @@ -4351,11 +4454,11 @@ impl Editor { multibuffer })?; - workspace.update(&mut cx, |workspace, cx| { + workspace.update_in(&mut cx, |workspace, window, cx| { let project = workspace.project().clone(); - let editor = - cx.new_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), true, cx)); - workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, cx); + let editor = cx + .new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), true, window, cx)); + workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx); editor.update(cx, |editor, cx| { editor.highlight_background::( &ranges_to_highlight, @@ -4376,7 +4479,8 @@ impl Editor { pub fn add_code_action_provider( &mut self, provider: Rc, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if self .code_action_providers @@ -4387,16 +4491,21 @@ impl Editor { } self.code_action_providers.push(provider); - self.refresh_code_actions(cx); + self.refresh_code_actions(window, cx); } - pub fn remove_code_action_provider(&mut self, id: Arc, cx: &mut ViewContext) { + pub fn remove_code_action_provider( + &mut self, + id: Arc, + window: &mut Window, + cx: &mut Context, + ) { self.code_action_providers .retain(|provider| provider.id() != id); - self.refresh_code_actions(cx); + self.refresh_code_actions(window, cx); } - fn refresh_code_actions(&mut self, cx: &mut ViewContext) -> Option<()> { + fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context) -> Option<()> { let buffer = self.buffer.read(cx); let newest_selection = self.selections.newest_anchor().clone(); if newest_selection.head().diff_base_anchor.is_some() { @@ -4408,17 +4517,17 @@ impl Editor { return None; } - self.code_actions_task = Some(cx.spawn(|this, mut cx| async move { + self.code_actions_task = Some(cx.spawn_in(window, |this, mut cx| async move { cx.background_executor() .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT) .await; - let (providers, tasks) = this.update(&mut cx, |this, cx| { + let (providers, tasks) = this.update_in(&mut cx, |this, window, cx| { let providers = this.code_action_providers.clone(); let tasks = this .code_action_providers .iter() - .map(|provider| provider.code_actions(&start_buffer, start..end, cx)) + .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx)) .collect::>(); (providers, tasks) })?; @@ -4456,23 +4565,24 @@ impl Editor { None } - fn start_inline_blame_timer(&mut self, cx: &mut ViewContext) { + fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context) { if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() { self.show_git_blame_inline = false; - self.show_git_blame_inline_delay_task = Some(cx.spawn(|this, mut cx| async move { - cx.background_executor().timer(delay).await; + self.show_git_blame_inline_delay_task = + Some(cx.spawn_in(window, |this, mut cx| async move { + cx.background_executor().timer(delay).await; - this.update(&mut cx, |this, cx| { - this.show_git_blame_inline = true; - cx.notify(); - }) - .log_err(); - })); + this.update(&mut cx, |this, cx| { + this.show_git_blame_inline = true; + cx.notify(); + }) + .log_err(); + })); } } - fn refresh_document_highlights(&mut self, cx: &mut ViewContext) -> Option<()> { + fn refresh_document_highlights(&mut self, cx: &mut Context) -> Option<()> { if self.pending_rename.is_some() { return None; } @@ -4580,7 +4690,8 @@ impl Editor { &mut self, debounce: bool, user_requested: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Option<()> { let provider = self.inline_completion_provider()?; let cursor = self.selections.newest_anchor().head(); @@ -4590,14 +4701,14 @@ impl Editor { if !user_requested && (!self.enable_inline_completions || !self.should_show_inline_completions(&buffer, cursor_buffer_position, cx) - || !self.is_focused(cx) + || !self.is_focused(window) || buffer.read(cx).is_empty()) { self.discard_inline_completion(false, cx); return None; } - self.update_visible_inline_completion(cx); + self.update_visible_inline_completion(window, cx); provider.refresh(buffer, cursor_buffer_position, debounce, cx); Some(()) } @@ -4605,7 +4716,8 @@ impl Editor { fn cycle_inline_completion( &mut self, direction: Direction, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Option<()> { let provider = self.inline_completion_provider()?; let cursor = self.selections.newest_anchor().head(); @@ -4618,28 +4730,38 @@ impl Editor { } provider.cycle(buffer, cursor_buffer_position, direction, cx); - self.update_visible_inline_completion(cx); + self.update_visible_inline_completion(window, cx); Some(()) } - pub fn show_inline_completion(&mut self, _: &ShowInlineCompletion, cx: &mut ViewContext) { + pub fn show_inline_completion( + &mut self, + _: &ShowInlineCompletion, + window: &mut Window, + cx: &mut Context, + ) { if !self.has_active_inline_completion() { - self.refresh_inline_completion(false, true, cx); + self.refresh_inline_completion(false, true, window, cx); return; } - self.update_visible_inline_completion(cx); + self.update_visible_inline_completion(window, cx); } - pub fn display_cursor_names(&mut self, _: &DisplayCursorNames, cx: &mut ViewContext) { - self.show_cursor_names(cx); + pub fn display_cursor_names( + &mut self, + _: &DisplayCursorNames, + window: &mut Window, + cx: &mut Context, + ) { + self.show_cursor_names(window, cx); } - fn show_cursor_names(&mut self, cx: &mut ViewContext) { + fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context) { self.show_cursor_names = true; cx.notify(); - cx.spawn(|this, mut cx| async move { + cx.spawn_in(window, |this, mut cx| async move { cx.background_executor().timer(CURSORS_VISIBLE_FOR).await; this.update(&mut cx, |this, cx| { this.show_cursor_names = false; @@ -4650,11 +4772,18 @@ impl Editor { .detach(); } - pub fn next_inline_completion(&mut self, _: &NextInlineCompletion, cx: &mut ViewContext) { + pub fn next_inline_completion( + &mut self, + _: &NextInlineCompletion, + window: &mut Window, + cx: &mut Context, + ) { if self.has_active_inline_completion() { - self.cycle_inline_completion(Direction::Next, cx); + self.cycle_inline_completion(Direction::Next, window, cx); } else { - let is_copilot_disabled = self.refresh_inline_completion(false, true, cx).is_none(); + let is_copilot_disabled = self + .refresh_inline_completion(false, true, window, cx) + .is_none(); if is_copilot_disabled { cx.propagate(); } @@ -4664,12 +4793,15 @@ impl Editor { pub fn previous_inline_completion( &mut self, _: &PreviousInlineCompletion, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if self.has_active_inline_completion() { - self.cycle_inline_completion(Direction::Prev, cx); + self.cycle_inline_completion(Direction::Prev, window, cx); } else { - let is_copilot_disabled = self.refresh_inline_completion(false, true, cx).is_none(); + let is_copilot_disabled = self + .refresh_inline_completion(false, true, window, cx) + .is_none(); if is_copilot_disabled { cx.propagate(); } @@ -4679,7 +4811,8 @@ impl Editor { pub fn accept_inline_completion( &mut self, _: &AcceptInlineCompletion, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let buffer = self.buffer.read(cx); let snapshot = buffer.snapshot(cx); @@ -4693,13 +4826,13 @@ impl Editor { && cursor.column <= current_indent.len && current_indent.len <= suggested_indent.len { - self.tab(&Default::default(), cx); + self.tab(&Default::default(), window, cx); return; } } if self.show_inline_completions_in_menu(cx) { - self.hide_context_menu(cx); + self.hide_context_menu(window, cx); } let Some(active_inline_completion) = self.active_inline_completion.as_ref() else { @@ -4711,7 +4844,7 @@ impl Editor { match &active_inline_completion.completion { InlineCompletion::Move(position) => { let position = *position; - self.change_selections(Some(Autoscroll::newest()), cx, |selections| { + self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| { selections.select_anchor_ranges([position..position]); }); } @@ -4727,13 +4860,13 @@ impl Editor { buffer.edit(edits.iter().cloned(), None, cx) }); - self.change_selections(None, cx, |s| { + self.change_selections(None, window, cx, |s| { s.select_anchor_ranges([last_edit_end..last_edit_end]) }); - self.update_visible_inline_completion(cx); + self.update_visible_inline_completion(window, cx); if self.active_inline_completion.is_none() { - self.refresh_inline_completion(true, true, cx); + self.refresh_inline_completion(true, true, window, cx); } cx.notify(); @@ -4744,7 +4877,8 @@ impl Editor { pub fn accept_partial_inline_completion( &mut self, _: &AcceptPartialInlineCompletion, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let Some(active_inline_completion) = self.active_inline_completion.as_ref() else { return; @@ -4758,7 +4892,7 @@ impl Editor { match &active_inline_completion.completion { InlineCompletion::Move(position) => { let position = *position; - self.change_selections(Some(Autoscroll::newest()), cx, |selections| { + self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| { selections.select_anchor_ranges([position..position]); }); } @@ -4794,12 +4928,12 @@ impl Editor { text: partial_completion.clone().into(), }); - self.insert_with_autoindent_mode(&partial_completion, None, cx); + self.insert_with_autoindent_mode(&partial_completion, None, window, cx); - self.refresh_inline_completion(true, true, cx); + self.refresh_inline_completion(true, true, window, cx); cx.notify(); } else { - self.accept_inline_completion(&Default::default(), cx); + self.accept_inline_completion(&Default::default(), window, cx); } } } @@ -4808,7 +4942,7 @@ impl Editor { fn discard_inline_completion( &mut self, should_report_inline_completion_event: bool, - cx: &mut ViewContext, + cx: &mut Context, ) -> bool { if should_report_inline_completion_event { self.report_inline_completion_event(false, cx); @@ -4821,7 +4955,7 @@ impl Editor { self.take_active_inline_completion(cx).is_some() } - fn report_inline_completion_event(&self, accepted: bool, cx: &AppContext) { + fn report_inline_completion_event(&self, accepted: bool, cx: &App) { let Some(provider) = self.inline_completion_provider() else { return; }; @@ -4857,7 +4991,7 @@ impl Editor { fn take_active_inline_completion( &mut self, - cx: &mut ViewContext, + cx: &mut Context, ) -> Option { let active_inline_completion = self.active_inline_completion.take()?; self.splice_inlays(active_inline_completion.inlay_ids, Default::default(), cx); @@ -4865,7 +4999,11 @@ impl Editor { Some(active_inline_completion.completion) } - fn update_visible_inline_completion(&mut self, cx: &mut ViewContext) -> Option<()> { + fn update_visible_inline_completion( + &mut self, + window: &mut Window, + cx: &mut Context, + ) -> Option<()> { let selection = self.selections.newest_anchor(); let cursor = selection.head(); let multibuffer = self.buffer.read(cx).snapshot(cx); @@ -4997,7 +5135,7 @@ impl Editor { }); if self.show_inline_completions_in_menu(cx) && self.has_active_completions_menu() { - if let Some(hint) = self.inline_completion_menu_hint(cx) { + if let Some(hint) = self.inline_completion_menu_hint(window, cx) { match self.context_menu.borrow_mut().as_mut() { Some(CodeContextMenu::Completions(menu)) => { menu.show_inline_completion_hint(hint); @@ -5014,11 +5152,12 @@ impl Editor { fn inline_completion_menu_hint( &self, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Option { let provider = self.inline_completion_provider()?; if self.has_active_inline_completion() { - let editor_snapshot = self.snapshot(cx); + let editor_snapshot = self.snapshot(window, cx); let text = match &self.active_inline_completion.as_ref()?.completion { InlineCompletion::Edit { @@ -5056,7 +5195,7 @@ impl Editor { Some(self.inline_completion_provider.as_ref()?.provider.clone()) } - fn show_inline_completions_in_menu(&self, cx: &AppContext) -> bool { + fn show_inline_completions_in_menu(&self, cx: &App) -> bool { let by_provider = matches!( self.menu_inline_completions_policy, MenuInlineCompletionsPolicy::ByProvider @@ -5074,7 +5213,7 @@ impl Editor { _style: &EditorStyle, row: DisplayRow, is_active: bool, - cx: &mut ViewContext, + cx: &mut Context, ) -> Option { if self.available_code_actions.is_some() { Some( @@ -5085,23 +5224,25 @@ impl Editor { .toggle_state(is_active) .tooltip({ let focus_handle = self.focus_handle.clone(); - move |cx| { + move |window, cx| { Tooltip::for_action_in( "Toggle Code Actions", &ToggleCodeActions { deployed_from_indicator: None, }, &focus_handle, + window, cx, ) } }) - .on_click(cx.listener(move |editor, _e, cx| { - editor.focus(cx); + .on_click(cx.listener(move |editor, _e, window, cx| { + window.focus(&editor.focus_handle(cx)); editor.toggle_code_actions( &ToggleCodeActions { deployed_from_indicator: Some(row), }, + window, cx, ); })), @@ -5123,11 +5264,11 @@ impl Editor { } fn build_tasks_context( - project: &Model, - buffer: &Model, + project: &Entity, + buffer: &Entity, buffer_row: u32, tasks: &Arc, - cx: &mut ViewContext, + cx: &mut Context, ) -> Task> { let position = Point::new(buffer_row, tasks.column); let range_start = buffer.read(cx).anchor_at(position, Bias::Right); @@ -5150,7 +5291,12 @@ impl Editor { }) } - pub fn spawn_nearest_task(&mut self, action: &SpawnNearestTask, cx: &mut ViewContext) { + pub fn spawn_nearest_task( + &mut self, + action: &SpawnNearestTask, + window: &mut Window, + cx: &mut Context, + ) { let Some((workspace, _)) = self.workspace.clone() else { return; }; @@ -5170,7 +5316,7 @@ impl Editor { let reveal_strategy = action.reveal; let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx); - cx.spawn(|_, mut cx| async move { + cx.spawn_in(window, |_, mut cx| async move { let context = task_context.await?; let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?; @@ -5194,8 +5340,8 @@ impl Editor { fn find_closest_task( &mut self, - cx: &mut ViewContext, - ) -> Option<(Model, u32, Arc)> { + cx: &mut Context, + ) -> Option<(Entity, u32, Arc)> { let cursor_row = self.selections.newest_adjusted(cx).head().row; let ((buffer_id, row), tasks) = self @@ -5210,8 +5356,8 @@ impl Editor { fn find_enclosing_node_task( &mut self, - cx: &mut ViewContext, - ) -> Option<(Model, u32, Arc)> { + cx: &mut Context, + ) -> Option<(Entity, u32, Arc)> { let snapshot = self.buffer.read(cx).snapshot(cx); let offset = self.selections.newest::(cx).head(); let excerpt = snapshot.excerpt_containing(offset..offset)?; @@ -5253,19 +5399,20 @@ impl Editor { _style: &EditorStyle, is_active: bool, row: DisplayRow, - cx: &mut ViewContext, + cx: &mut Context, ) -> IconButton { IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play) .shape(ui::IconButtonShape::Square) .icon_size(IconSize::XSmall) .icon_color(Color::Muted) .toggle_state(is_active) - .on_click(cx.listener(move |editor, _e, cx| { - editor.focus(cx); + .on_click(cx.listener(move |editor, _e, window, cx| { + window.focus(&editor.focus_handle(cx)); editor.toggle_code_actions( &ToggleCodeActions { deployed_from_indicator: Some(row), }, + window, cx, ); })) @@ -5306,11 +5453,12 @@ impl Editor { style: &EditorStyle, max_height_in_lines: u32, y_flipped: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Option { self.context_menu.borrow().as_ref().and_then(|menu| { if menu.visible() { - Some(menu.render(style, max_height_in_lines, y_flipped, cx)) + Some(menu.render(style, max_height_in_lines, y_flipped, window, cx)) } else { None } @@ -5321,7 +5469,7 @@ impl Editor { &self, style: &EditorStyle, max_size: Size, - cx: &mut ViewContext, + cx: &mut Context, ) -> Option { self.context_menu.borrow().as_ref().and_then(|menu| { if menu.visible() { @@ -5337,12 +5485,16 @@ impl Editor { }) } - fn hide_context_menu(&mut self, cx: &mut ViewContext) -> Option { + fn hide_context_menu( + &mut self, + window: &mut Window, + cx: &mut Context, + ) -> Option { cx.notify(); self.completion_tasks.clear(); let context_menu = self.context_menu.borrow_mut().take(); if context_menu.is_some() && !self.show_inline_completions_in_menu(cx) { - self.update_visible_inline_completion(cx); + self.update_visible_inline_completion(window, cx); } context_menu } @@ -5351,7 +5503,7 @@ impl Editor { &mut self, choices: &Vec, selection: Range, - cx: &mut ViewContext, + cx: &mut Context, ) { if selection.start.buffer_id.is_none() { return; @@ -5371,7 +5523,8 @@ impl Editor { &mut self, insertion_ranges: &[Range], snippet: Snippet, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Result<()> { struct Tabstop { is_end_tabstop: bool, @@ -5428,7 +5581,7 @@ impl Editor { .collect::>() }); if let Some(tabstop) = tabstops.first() { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select_ranges(tabstop.ranges.iter().cloned()); }); @@ -5497,15 +5650,28 @@ impl Editor { Ok(()) } - pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext) -> bool { - self.move_to_snippet_tabstop(Bias::Right, cx) + pub fn move_to_next_snippet_tabstop( + &mut self, + window: &mut Window, + cx: &mut Context, + ) -> bool { + self.move_to_snippet_tabstop(Bias::Right, window, cx) } - pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext) -> bool { - self.move_to_snippet_tabstop(Bias::Left, cx) + pub fn move_to_prev_snippet_tabstop( + &mut self, + window: &mut Window, + cx: &mut Context, + ) -> bool { + self.move_to_snippet_tabstop(Bias::Left, window, cx) } - pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext) -> bool { + pub fn move_to_snippet_tabstop( + &mut self, + bias: Bias, + window: &mut Window, + cx: &mut Context, + ) -> bool { if let Some(mut snippet) = self.snippet_stack.pop() { match bias { Bias::Left => { @@ -5526,7 +5692,7 @@ impl Editor { } } if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select_anchor_ranges(current_ranges.iter().cloned()) }); @@ -5547,16 +5713,16 @@ impl Editor { false } - pub fn clear(&mut self, cx: &mut ViewContext) { - self.transact(cx, |this, cx| { - this.select_all(&SelectAll, cx); - this.insert("", cx); + pub fn clear(&mut self, window: &mut Window, cx: &mut Context) { + self.transact(window, cx, |this, window, cx| { + this.select_all(&SelectAll, window, cx); + this.insert("", window, cx); }); } - pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext) { - self.transact(cx, |this, cx| { - this.select_autoclose_pair(cx); + pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context) { + self.transact(window, cx, |this, window, cx| { + this.select_autoclose_pair(window, cx); let mut linked_ranges = HashMap::<_, Vec<_>>::default(); if !this.linked_edit_ranges.is_empty() { let selections = this.selections.all::(cx); @@ -5617,8 +5783,10 @@ impl Editor { } this.signature_help_state.set_backspace_pressed(true); - this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); - this.insert("", cx); + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { + s.select(selections) + }); + this.insert("", window, cx); let empty_str: Arc = Arc::from(""); for (buffer, edits) in linked_ranges { let snapshot = buffer.read(cx).snapshot(); @@ -5645,14 +5813,14 @@ impl Editor { this.edit(edits, None, cx); }) } - this.refresh_inline_completion(true, false, cx); - linked_editing_ranges::refresh_linked_ranges(this, cx); + this.refresh_inline_completion(true, false, window, cx); + linked_editing_ranges::refresh_linked_ranges(this, window, cx); }); } - pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext) { - self.transact(cx, |this, cx| { - this.change_selections(Some(Autoscroll::fit()), cx, |s| { + pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context) { + self.transact(window, cx, |this, window, cx| { + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { let line_mode = s.line_mode; s.move_with(|map, selection| { if selection.is_empty() && !line_mode { @@ -5663,21 +5831,21 @@ impl Editor { } }) }); - this.insert("", cx); - this.refresh_inline_completion(true, false, cx); + this.insert("", window, cx); + this.refresh_inline_completion(true, false, window, cx); }); } - pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext) { - if self.move_to_prev_snippet_tabstop(cx) { + pub fn tab_prev(&mut self, _: &TabPrev, window: &mut Window, cx: &mut Context) { + if self.move_to_prev_snippet_tabstop(window, cx) { return; } - self.outdent(&Outdent, cx); + self.outdent(&Outdent, window, cx); } - pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext) { - if self.move_to_next_snippet_tabstop(cx) || self.read_only(cx) { + pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context) { + if self.move_to_next_snippet_tabstop(window, cx) || self.read_only(cx) { return; } @@ -5748,14 +5916,16 @@ impl Editor { row_delta += tab_size.len; } - self.transact(cx, |this, cx| { + self.transact(window, cx, |this, window, cx| { this.buffer.update(cx, |b, cx| b.edit(edits, None, cx)); - this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); - this.refresh_inline_completion(true, false, cx); + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { + s.select(selections) + }); + this.refresh_inline_completion(true, false, window, cx); }); } - pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext) { + pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context) { if self.read_only(cx) { return; } @@ -5775,9 +5945,11 @@ impl Editor { Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx); } - self.transact(cx, |this, cx| { + self.transact(window, cx, |this, window, cx| { this.buffer.update(cx, |b, cx| b.edit(edits, None, cx)); - this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { + s.select(selections) + }); }); } @@ -5787,7 +5959,7 @@ impl Editor { selection: &mut Selection, edits: &mut Vec<(Range, String)>, delta_for_start_row: u32, - cx: &AppContext, + cx: &App, ) -> u32 { let settings = buffer.settings_at(selection.start, cx); let tab_size = settings.tab_size.get(); @@ -5857,7 +6029,7 @@ impl Editor { } } - pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext) { + pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context) { if self.read_only(cx) { return; } @@ -5912,7 +6084,7 @@ impl Editor { } } - self.transact(cx, |this, cx| { + self.transact(window, cx, |this, window, cx| { this.buffer.update(cx, |buffer, cx| { let empty_str: Arc = Arc::default(); buffer.edit( @@ -5924,11 +6096,13 @@ impl Editor { ); }); let selections = this.selections.all::(cx); - this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { + s.select(selections) + }); }); } - pub fn autoindent(&mut self, _: &AutoIndent, cx: &mut ViewContext) { + pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context) { if self.read_only(cx) { return; } @@ -5938,16 +6112,18 @@ impl Editor { .into_iter() .map(|s| s.range()); - self.transact(cx, |this, cx| { + self.transact(window, cx, |this, window, cx| { this.buffer.update(cx, |buffer, cx| { buffer.autoindent_ranges(selections, cx); }); let selections = this.selections.all::(cx); - this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { + s.select(selections) + }); }); } - pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext) { + pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let selections = self.selections.all::(cx); @@ -5997,7 +6173,7 @@ impl Editor { edit_ranges.push(edit_start..edit_end); } - self.transact(cx, |this, cx| { + self.transact(window, cx, |this, window, cx| { let buffer = this.buffer.update(cx, |buffer, cx| { let empty_str: Arc = Arc::default(); buffer.edit( @@ -6023,13 +6199,18 @@ impl Editor { }) .collect(); - this.change_selections(Some(Autoscroll::fit()), cx, |s| { + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select(new_selections); }); }); } - pub fn join_lines_impl(&mut self, insert_whitespace: bool, cx: &mut ViewContext) { + pub fn join_lines_impl( + &mut self, + insert_whitespace: bool, + window: &mut Window, + cx: &mut Context, + ) { if self.read_only(cx) { return; } @@ -6063,7 +6244,7 @@ impl Editor { cursor_positions.push(anchor..anchor); } - self.transact(cx, |this, cx| { + self.transact(window, cx, |this, window, cx| { for row_range in row_ranges.into_iter().rev() { for row in row_range.iter_rows().rev() { let end_of_line = Point::new(row.0, snapshot.line_len(row)); @@ -6084,38 +6265,43 @@ impl Editor { } } - this.change_selections(Some(Autoscroll::fit()), cx, |s| { + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select_anchor_ranges(cursor_positions) }); }); } - pub fn join_lines(&mut self, _: &JoinLines, cx: &mut ViewContext) { - self.join_lines_impl(true, cx); + pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context) { + self.join_lines_impl(true, window, cx); } pub fn sort_lines_case_sensitive( &mut self, _: &SortLinesCaseSensitive, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.manipulate_lines(cx, |lines| lines.sort()) + self.manipulate_lines(window, cx, |lines| lines.sort()) } pub fn sort_lines_case_insensitive( &mut self, _: &SortLinesCaseInsensitive, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.manipulate_lines(cx, |lines| lines.sort_by_key(|line| line.to_lowercase())) + self.manipulate_lines(window, cx, |lines| { + lines.sort_by_key(|line| line.to_lowercase()) + }) } pub fn unique_lines_case_insensitive( &mut self, _: &UniqueLinesCaseInsensitive, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.manipulate_lines(cx, |lines| { + self.manipulate_lines(window, cx, |lines| { let mut seen = HashSet::default(); lines.retain(|line| seen.insert(line.to_lowercase())); }) @@ -6124,59 +6310,72 @@ impl Editor { pub fn unique_lines_case_sensitive( &mut self, _: &UniqueLinesCaseSensitive, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.manipulate_lines(cx, |lines| { + self.manipulate_lines(window, cx, |lines| { let mut seen = HashSet::default(); lines.retain(|line| seen.insert(*line)); }) } - pub fn revert_file(&mut self, _: &RevertFile, cx: &mut ViewContext) { + pub fn revert_file(&mut self, _: &RevertFile, window: &mut Window, cx: &mut Context) { let mut revert_changes = HashMap::default(); - let snapshot = self.snapshot(cx); + let snapshot = self.snapshot(window, cx); for hunk in snapshot .hunks_for_ranges(Some(Point::zero()..snapshot.buffer_snapshot.max_point()).into_iter()) { self.prepare_revert_change(&mut revert_changes, &hunk, cx); } if !revert_changes.is_empty() { - self.transact(cx, |editor, cx| { - editor.revert(revert_changes, cx); + self.transact(window, cx, |editor, window, cx| { + editor.revert(revert_changes, window, cx); }); } } - pub fn reload_file(&mut self, _: &ReloadFile, cx: &mut ViewContext) { + pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context) { let Some(project) = self.project.clone() else { return; }; - self.reload(project, cx).detach_and_notify_err(cx); + self.reload(project, window, cx) + .detach_and_notify_err(window, cx); } - pub fn revert_selected_hunks(&mut self, _: &RevertSelectedHunks, cx: &mut ViewContext) { + pub fn revert_selected_hunks( + &mut self, + _: &RevertSelectedHunks, + window: &mut Window, + cx: &mut Context, + ) { let selections = self.selections.all(cx).into_iter().map(|s| s.range()); - self.revert_hunks_in_ranges(selections, cx); + self.revert_hunks_in_ranges(selections, window, cx); } fn revert_hunks_in_ranges( &mut self, ranges: impl Iterator>, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let mut revert_changes = HashMap::default(); - let snapshot = self.snapshot(cx); + let snapshot = self.snapshot(window, cx); for hunk in &snapshot.hunks_for_ranges(ranges) { self.prepare_revert_change(&mut revert_changes, &hunk, cx); } if !revert_changes.is_empty() { - self.transact(cx, |editor, cx| { - editor.revert(revert_changes, cx); + self.transact(window, cx, |editor, window, cx| { + editor.revert(revert_changes, window, cx); }); } } - pub fn open_active_item_in_terminal(&mut self, _: &OpenInTerminal, cx: &mut ViewContext) { + pub fn open_active_item_in_terminal( + &mut self, + _: &OpenInTerminal, + window: &mut Window, + cx: &mut Context, + ) { if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| { let project_path = buffer.read(cx).project_path(cx)?; let project = self.project.as_ref()?.read(cx); @@ -6189,7 +6388,7 @@ impl Editor { .to_path_buf(); Some(parent) }) { - cx.dispatch_action(OpenTerminal { working_directory }.boxed_clone()); + window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx); } } @@ -6197,7 +6396,7 @@ impl Editor { &self, revert_changes: &mut HashMap, Rope)>>, hunk: &MultiBufferDiffHunk, - cx: &mut WindowContext, + cx: &mut App, ) -> Option<()> { let buffer = self.buffer.read(cx); let change_set = buffer.change_set_for(hunk.buffer_id)?; @@ -6225,16 +6424,20 @@ impl Editor { } } - pub fn reverse_lines(&mut self, _: &ReverseLines, cx: &mut ViewContext) { - self.manipulate_lines(cx, |lines| lines.reverse()) + pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context) { + self.manipulate_lines(window, cx, |lines| lines.reverse()) } - pub fn shuffle_lines(&mut self, _: &ShuffleLines, cx: &mut ViewContext) { - self.manipulate_lines(cx, |lines| lines.shuffle(&mut thread_rng())) + pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context) { + self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng())) } - fn manipulate_lines(&mut self, cx: &mut ViewContext, mut callback: Fn) - where + fn manipulate_lines( + &mut self, + window: &mut Window, + cx: &mut Context, + mut callback: Fn, + ) where Fn: FnMut(&mut Vec<&str>), { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); @@ -6293,7 +6496,7 @@ impl Editor { } } - self.transact(cx, |this, cx| { + self.transact(window, cx, |this, window, cx| { let buffer = this.buffer.update(cx, |buffer, cx| { buffer.edit(edits, None, cx); buffer.snapshot(cx) @@ -6315,7 +6518,7 @@ impl Editor { }) .collect(); - this.change_selections(Some(Autoscroll::fit()), cx, |s| { + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select(new_selections); }); @@ -6323,36 +6526,62 @@ impl Editor { }); } - pub fn convert_to_upper_case(&mut self, _: &ConvertToUpperCase, cx: &mut ViewContext) { - self.manipulate_text(cx, |text| text.to_uppercase()) + pub fn convert_to_upper_case( + &mut self, + _: &ConvertToUpperCase, + window: &mut Window, + cx: &mut Context, + ) { + self.manipulate_text(window, cx, |text| text.to_uppercase()) } - pub fn convert_to_lower_case(&mut self, _: &ConvertToLowerCase, cx: &mut ViewContext) { - self.manipulate_text(cx, |text| text.to_lowercase()) + pub fn convert_to_lower_case( + &mut self, + _: &ConvertToLowerCase, + window: &mut Window, + cx: &mut Context, + ) { + self.manipulate_text(window, cx, |text| text.to_lowercase()) } - pub fn convert_to_title_case(&mut self, _: &ConvertToTitleCase, cx: &mut ViewContext) { - self.manipulate_text(cx, |text| { + pub fn convert_to_title_case( + &mut self, + _: &ConvertToTitleCase, + window: &mut Window, + cx: &mut Context, + ) { + self.manipulate_text(window, cx, |text| { text.split('\n') .map(|line| line.to_case(Case::Title)) .join("\n") }) } - pub fn convert_to_snake_case(&mut self, _: &ConvertToSnakeCase, cx: &mut ViewContext) { - self.manipulate_text(cx, |text| text.to_case(Case::Snake)) + pub fn convert_to_snake_case( + &mut self, + _: &ConvertToSnakeCase, + window: &mut Window, + cx: &mut Context, + ) { + self.manipulate_text(window, cx, |text| text.to_case(Case::Snake)) } - pub fn convert_to_kebab_case(&mut self, _: &ConvertToKebabCase, cx: &mut ViewContext) { - self.manipulate_text(cx, |text| text.to_case(Case::Kebab)) + pub fn convert_to_kebab_case( + &mut self, + _: &ConvertToKebabCase, + window: &mut Window, + cx: &mut Context, + ) { + self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab)) } pub fn convert_to_upper_camel_case( &mut self, _: &ConvertToUpperCamelCase, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.manipulate_text(cx, |text| { + self.manipulate_text(window, cx, |text| { text.split('\n') .map(|line| line.to_case(Case::UpperCamel)) .join("\n") @@ -6362,17 +6591,19 @@ impl Editor { pub fn convert_to_lower_camel_case( &mut self, _: &ConvertToLowerCamelCase, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.manipulate_text(cx, |text| text.to_case(Case::Camel)) + self.manipulate_text(window, cx, |text| text.to_case(Case::Camel)) } pub fn convert_to_opposite_case( &mut self, _: &ConvertToOppositeCase, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.manipulate_text(cx, |text| { + self.manipulate_text(window, cx, |text| { text.chars() .fold(String::with_capacity(text.len()), |mut t, c| { if c.is_uppercase() { @@ -6385,7 +6616,7 @@ impl Editor { }) } - fn manipulate_text(&mut self, cx: &mut ViewContext, mut callback: Fn) + fn manipulate_text(&mut self, window: &mut Window, cx: &mut Context, mut callback: Fn) where Fn: FnMut(&str) -> String, { @@ -6427,12 +6658,12 @@ impl Editor { edits.push((start..end, text)); } - self.transact(cx, |this, cx| { + self.transact(window, cx, |this, window, cx| { this.buffer.update(cx, |buffer, cx| { buffer.edit(edits, None, cx); }); - this.change_selections(Some(Autoscroll::fit()), cx, |s| { + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select(new_selections); }); @@ -6440,7 +6671,13 @@ impl Editor { }); } - pub fn duplicate(&mut self, upwards: bool, whole_lines: bool, cx: &mut ViewContext) { + pub fn duplicate( + &mut self, + upwards: bool, + whole_lines: bool, + window: &mut Window, + cx: &mut Context, + ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = &display_map.buffer_snapshot; let selections = self.selections.all::(cx); @@ -6488,7 +6725,7 @@ impl Editor { } } - self.transact(cx, |this, cx| { + self.transact(window, cx, |this, _, cx| { this.buffer.update(cx, |buffer, cx| { buffer.edit(edits, None, cx); }); @@ -6497,19 +6734,34 @@ impl Editor { }); } - pub fn duplicate_line_up(&mut self, _: &DuplicateLineUp, cx: &mut ViewContext) { - self.duplicate(true, true, cx); + pub fn duplicate_line_up( + &mut self, + _: &DuplicateLineUp, + window: &mut Window, + cx: &mut Context, + ) { + self.duplicate(true, true, window, cx); } - pub fn duplicate_line_down(&mut self, _: &DuplicateLineDown, cx: &mut ViewContext) { - self.duplicate(false, true, cx); + pub fn duplicate_line_down( + &mut self, + _: &DuplicateLineDown, + window: &mut Window, + cx: &mut Context, + ) { + self.duplicate(false, true, window, cx); } - pub fn duplicate_selection(&mut self, _: &DuplicateSelection, cx: &mut ViewContext) { - self.duplicate(false, false, cx); + pub fn duplicate_selection( + &mut self, + _: &DuplicateSelection, + window: &mut Window, + cx: &mut Context, + ) { + self.duplicate(false, false, window, cx); } - pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext) { + pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = self.buffer.read(cx).snapshot(cx); @@ -6595,21 +6847,26 @@ impl Editor { new_selections.append(&mut contiguous_row_selections); } - self.transact(cx, |this, cx| { + self.transact(window, cx, |this, window, cx| { this.unfold_ranges(&unfold_ranges, true, true, cx); this.buffer.update(cx, |buffer, cx| { for (range, text) in edits { buffer.edit([(range, text)], None, cx); } }); - this.fold_creases(refold_creases, true, cx); - this.change_selections(Some(Autoscroll::fit()), cx, |s| { + this.fold_creases(refold_creases, true, window, cx); + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select(new_selections); }) }); } - pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext) { + pub fn move_line_down( + &mut self, + _: &MoveLineDown, + window: &mut Window, + cx: &mut Context, + ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = self.buffer.read(cx).snapshot(cx); @@ -6685,22 +6942,24 @@ impl Editor { new_selections.append(&mut contiguous_row_selections); } - self.transact(cx, |this, cx| { + self.transact(window, cx, |this, window, cx| { this.unfold_ranges(&unfold_ranges, true, true, cx); this.buffer.update(cx, |buffer, cx| { for (range, text) in edits { buffer.edit([(range, text)], None, cx); } }); - this.fold_creases(refold_creases, true, cx); - this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections)); + this.fold_creases(refold_creases, true, window, cx); + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { + s.select(new_selections) + }); }); } - pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext) { - let text_layout_details = &self.text_layout_details(cx); - self.transact(cx, |this, cx| { - let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| { + pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context) { + let text_layout_details = &self.text_layout_details(window); + self.transact(window, cx, |this, window, cx| { + let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { let mut edits: Vec<(Range, String)> = Default::default(); let line_mode = s.line_mode; s.move_with(|display_map, selection| { @@ -6749,17 +7008,17 @@ impl Editor { this.buffer .update(cx, |buffer, cx| buffer.edit(edits, None, cx)); let selections = this.selections.all::(cx); - this.change_selections(Some(Autoscroll::fit()), cx, |s| { + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select(selections); }); }); } - pub fn rewrap(&mut self, _: &Rewrap, cx: &mut ViewContext) { + pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context) { self.rewrap_impl(IsVimMode::No, cx) } - pub fn rewrap_impl(&mut self, is_vim_mode: IsVimMode, cx: &mut ViewContext) { + pub fn rewrap_impl(&mut self, is_vim_mode: IsVimMode, cx: &mut Context) { let buffer = self.buffer.read(cx).snapshot(cx); let selections = self.selections.all::(cx); let mut selections = selections.iter().peekable(); @@ -6941,7 +7200,7 @@ impl Editor { .update(cx, |buffer, cx| buffer.edit(edits, None, cx)); } - pub fn cut_common(&mut self, cx: &mut ViewContext) -> ClipboardItem { + pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context) -> ClipboardItem { let mut text = String::new(); let buffer = self.buffer.read(cx).snapshot(cx); let mut selections = self.selections.all::(cx); @@ -6980,33 +7239,38 @@ impl Editor { } } - self.transact(cx, |this, cx| { - this.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.transact(window, cx, |this, window, cx| { + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select(selections); }); - this.insert("", cx); + this.insert("", window, cx); }); ClipboardItem::new_string_with_json_metadata(text, clipboard_selections) } - pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext) { - let item = self.cut_common(cx); + pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context) { + let item = self.cut_common(window, cx); cx.write_to_clipboard(item); } - pub fn kill_ring_cut(&mut self, _: &KillRingCut, cx: &mut ViewContext) { - self.change_selections(None, cx, |s| { + pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context) { + self.change_selections(None, window, cx, |s| { s.move_with(|snapshot, sel| { if sel.is_empty() { sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row())) } }); }); - let item = self.cut_common(cx); + let item = self.cut_common(window, cx); cx.set_global(KillRing(item)) } - pub fn kill_ring_yank(&mut self, _: &KillRingYank, cx: &mut ViewContext) { + pub fn kill_ring_yank( + &mut self, + _: &KillRingYank, + window: &mut Window, + cx: &mut Context, + ) { let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() { if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() { (kill_ring.text().to_string(), kill_ring.metadata_json()) @@ -7016,10 +7280,10 @@ impl Editor { } else { return; }; - self.do_paste(&text, metadata, false, cx); + self.do_paste(&text, metadata, false, window, cx); } - pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext) { + pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context) { let selections = self.selections.all::(cx); let buffer = self.buffer.read(cx).read(cx); let mut text = String::new(); @@ -7065,7 +7329,8 @@ impl Editor { text: &String, clipboard_selections: Option>, handle_entire_lines: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if self.read_only(cx) { return; @@ -7073,7 +7338,7 @@ impl Editor { let clipboard_text = Cow::Borrowed(text); - self.transact(cx, |this, cx| { + self.transact(window, cx, |this, window, cx| { if let Some(mut clipboard_selections) = clipboard_selections { let old_selections = this.selections.all::(cx); let all_selections_were_entire_line = @@ -7141,14 +7406,16 @@ impl Editor { }); let selections = this.selections.all::(cx); - this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { + s.select(selections) + }); } else { - this.insert(&clipboard_text, cx); + this.insert(&clipboard_text, window, cx); } }); } - pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext) { + pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context) { if let Some(item) = cx.read_from_clipboard() { let entries = item.entries(); @@ -7160,14 +7427,15 @@ impl Editor { clipboard_string.text(), clipboard_string.metadata_json::>(), true, + window, cx, ), - _ => self.do_paste(&item.text().unwrap_or_default(), None, true, cx), + _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx), } } } - pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext) { + pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context) { if self.read_only(cx) { return; } @@ -7176,19 +7444,19 @@ impl Editor { if let Some((selections, _)) = self.selection_history.transaction(transaction_id).cloned() { - self.change_selections(None, cx, |s| { + self.change_selections(None, window, cx, |s| { s.select_anchors(selections.to_vec()); }); } self.request_autoscroll(Autoscroll::fit(), cx); - self.unmark_text(cx); - self.refresh_inline_completion(true, false, cx); + self.unmark_text(window, cx); + self.refresh_inline_completion(true, false, window, cx); cx.emit(EditorEvent::Edited { transaction_id }); cx.emit(EditorEvent::TransactionUndone { transaction_id }); } } - pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext) { + pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context) { if self.read_only(cx) { return; } @@ -7197,29 +7465,29 @@ impl Editor { if let Some((_, Some(selections))) = self.selection_history.transaction(transaction_id).cloned() { - self.change_selections(None, cx, |s| { + self.change_selections(None, window, cx, |s| { s.select_anchors(selections.to_vec()); }); } self.request_autoscroll(Autoscroll::fit(), cx); - self.unmark_text(cx); - self.refresh_inline_completion(true, false, cx); + self.unmark_text(window, cx); + self.refresh_inline_completion(true, false, window, cx); cx.emit(EditorEvent::Edited { transaction_id }); } } - pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext) { + pub fn finalize_last_transaction(&mut self, cx: &mut Context) { self.buffer .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx)); } - pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut ViewContext) { + pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context) { self.buffer .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx)); } - pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context) { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { let line_mode = s.line_mode; s.move_with(|map, selection| { let cursor = if selection.is_empty() && !line_mode { @@ -7232,14 +7500,14 @@ impl Editor { }) } - pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context) { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None)); }) } - pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context) { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { let line_mode = s.line_mode; s.move_with(|map, selection| { let cursor = if selection.is_empty() && !line_mode { @@ -7252,14 +7520,14 @@ impl Editor { }) } - pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context) { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None)); }) } - pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext) { - if self.take_rename(true, cx).is_some() { + pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context) { + if self.take_rename(true, window, cx).is_some() { return; } @@ -7268,11 +7536,11 @@ impl Editor { return; } - let text_layout_details = &self.text_layout_details(cx); + let text_layout_details = &self.text_layout_details(window); let selection_count = self.selections.count(); let first_selection = self.selections.first_anchor(); - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { let line_mode = s.line_mode; s.move_with(|map, selection| { if !selection.is_empty() && !line_mode { @@ -7295,8 +7563,13 @@ impl Editor { } } - pub fn move_up_by_lines(&mut self, action: &MoveUpByLines, cx: &mut ViewContext) { - if self.take_rename(true, cx).is_some() { + pub fn move_up_by_lines( + &mut self, + action: &MoveUpByLines, + window: &mut Window, + cx: &mut Context, + ) { + if self.take_rename(true, window, cx).is_some() { return; } @@ -7305,9 +7578,9 @@ impl Editor { return; } - let text_layout_details = &self.text_layout_details(cx); + let text_layout_details = &self.text_layout_details(window); - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { let line_mode = s.line_mode; s.move_with(|map, selection| { if !selection.is_empty() && !line_mode { @@ -7326,8 +7599,13 @@ impl Editor { }) } - pub fn move_down_by_lines(&mut self, action: &MoveDownByLines, cx: &mut ViewContext) { - if self.take_rename(true, cx).is_some() { + pub fn move_down_by_lines( + &mut self, + action: &MoveDownByLines, + window: &mut Window, + cx: &mut Context, + ) { + if self.take_rename(true, window, cx).is_some() { return; } @@ -7336,9 +7614,9 @@ impl Editor { return; } - let text_layout_details = &self.text_layout_details(cx); + let text_layout_details = &self.text_layout_details(window); - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { let line_mode = s.line_mode; s.move_with(|map, selection| { if !selection.is_empty() && !line_mode { @@ -7357,40 +7635,60 @@ impl Editor { }) } - pub fn select_down_by_lines(&mut self, action: &SelectDownByLines, cx: &mut ViewContext) { - let text_layout_details = &self.text_layout_details(cx); - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + pub fn select_down_by_lines( + &mut self, + action: &SelectDownByLines, + window: &mut Window, + cx: &mut Context, + ) { + let text_layout_details = &self.text_layout_details(window); + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_heads_with(|map, head, goal| { movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details) }) }) } - pub fn select_up_by_lines(&mut self, action: &SelectUpByLines, cx: &mut ViewContext) { - let text_layout_details = &self.text_layout_details(cx); - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + pub fn select_up_by_lines( + &mut self, + action: &SelectUpByLines, + window: &mut Window, + cx: &mut Context, + ) { + let text_layout_details = &self.text_layout_details(window); + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_heads_with(|map, head, goal| { movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details) }) }) } - pub fn select_page_up(&mut self, _: &SelectPageUp, cx: &mut ViewContext) { + pub fn select_page_up( + &mut self, + _: &SelectPageUp, + window: &mut Window, + cx: &mut Context, + ) { let Some(row_count) = self.visible_row_count() else { return; }; - let text_layout_details = &self.text_layout_details(cx); + let text_layout_details = &self.text_layout_details(window); - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_heads_with(|map, head, goal| { movement::up_by_rows(map, head, row_count, goal, false, text_layout_details) }) }) } - pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext) { - if self.take_rename(true, cx).is_some() { + pub fn move_page_up( + &mut self, + action: &MovePageUp, + window: &mut Window, + cx: &mut Context, + ) { + if self.take_rename(true, window, cx).is_some() { return; } @@ -7419,9 +7717,9 @@ impl Editor { Autoscroll::fit() }; - let text_layout_details = &self.text_layout_details(cx); + let text_layout_details = &self.text_layout_details(window); - self.change_selections(Some(autoscroll), cx, |s| { + self.change_selections(Some(autoscroll), window, cx, |s| { let line_mode = s.line_mode; s.move_with(|map, selection| { if !selection.is_empty() && !line_mode { @@ -7440,28 +7738,28 @@ impl Editor { }); } - pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext) { - let text_layout_details = &self.text_layout_details(cx); - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context) { + let text_layout_details = &self.text_layout_details(window); + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_heads_with(|map, head, goal| { movement::up(map, head, goal, false, text_layout_details) }) }) } - pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext) { - self.take_rename(true, cx); + pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context) { + self.take_rename(true, window, cx); if matches!(self.mode, EditorMode::SingleLine { .. }) { cx.propagate(); return; } - let text_layout_details = &self.text_layout_details(cx); + let text_layout_details = &self.text_layout_details(window); let selection_count = self.selections.count(); let first_selection = self.selections.first_anchor(); - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { let line_mode = s.line_mode; s.move_with(|map, selection| { if !selection.is_empty() && !line_mode { @@ -7484,22 +7782,32 @@ impl Editor { } } - pub fn select_page_down(&mut self, _: &SelectPageDown, cx: &mut ViewContext) { + pub fn select_page_down( + &mut self, + _: &SelectPageDown, + window: &mut Window, + cx: &mut Context, + ) { let Some(row_count) = self.visible_row_count() else { return; }; - let text_layout_details = &self.text_layout_details(cx); + let text_layout_details = &self.text_layout_details(window); - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_heads_with(|map, head, goal| { movement::down_by_rows(map, head, row_count, goal, false, text_layout_details) }) }) } - pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext) { - if self.take_rename(true, cx).is_some() { + pub fn move_page_down( + &mut self, + action: &MovePageDown, + window: &mut Window, + cx: &mut Context, + ) { + if self.take_rename(true, window, cx).is_some() { return; } @@ -7528,8 +7836,8 @@ impl Editor { Autoscroll::fit() }; - let text_layout_details = &self.text_layout_details(cx); - self.change_selections(Some(autoscroll), cx, |s| { + let text_layout_details = &self.text_layout_details(window); + self.change_selections(Some(autoscroll), window, cx, |s| { let line_mode = s.line_mode; s.move_with(|map, selection| { if !selection.is_empty() && !line_mode { @@ -7548,34 +7856,54 @@ impl Editor { }); } - pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext) { - let text_layout_details = &self.text_layout_details(cx); - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context) { + let text_layout_details = &self.text_layout_details(window); + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_heads_with(|map, head, goal| { movement::down(map, head, goal, false, text_layout_details) }) }); } - pub fn context_menu_first(&mut self, _: &ContextMenuFirst, cx: &mut ViewContext) { + pub fn context_menu_first( + &mut self, + _: &ContextMenuFirst, + _window: &mut Window, + cx: &mut Context, + ) { if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() { context_menu.select_first(self.completion_provider.as_deref(), cx); } } - pub fn context_menu_prev(&mut self, _: &ContextMenuPrev, cx: &mut ViewContext) { + pub fn context_menu_prev( + &mut self, + _: &ContextMenuPrev, + _window: &mut Window, + cx: &mut Context, + ) { if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() { context_menu.select_prev(self.completion_provider.as_deref(), cx); } } - pub fn context_menu_next(&mut self, _: &ContextMenuNext, cx: &mut ViewContext) { + pub fn context_menu_next( + &mut self, + _: &ContextMenuNext, + _window: &mut Window, + cx: &mut Context, + ) { if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() { context_menu.select_next(self.completion_provider.as_deref(), cx); } } - pub fn context_menu_last(&mut self, _: &ContextMenuLast, cx: &mut ViewContext) { + pub fn context_menu_last( + &mut self, + _: &ContextMenuLast, + _window: &mut Window, + cx: &mut Context, + ) { if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() { context_menu.select_last(self.completion_provider.as_deref(), cx); } @@ -7584,9 +7912,10 @@ impl Editor { pub fn move_to_previous_word_start( &mut self, _: &MoveToPreviousWordStart, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_cursors_with(|map, head, _| { ( movement::previous_word_start(map, head), @@ -7599,9 +7928,10 @@ impl Editor { pub fn move_to_previous_subword_start( &mut self, _: &MoveToPreviousSubwordStart, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_cursors_with(|map, head, _| { ( movement::previous_subword_start(map, head), @@ -7614,9 +7944,10 @@ impl Editor { pub fn select_to_previous_word_start( &mut self, _: &SelectToPreviousWordStart, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_heads_with(|map, head, _| { ( movement::previous_word_start(map, head), @@ -7629,9 +7960,10 @@ impl Editor { pub fn select_to_previous_subword_start( &mut self, _: &SelectToPreviousSubwordStart, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_heads_with(|map, head, _| { ( movement::previous_subword_start(map, head), @@ -7644,11 +7976,12 @@ impl Editor { pub fn delete_to_previous_word_start( &mut self, action: &DeleteToPreviousWordStart, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.transact(cx, |this, cx| { - this.select_autoclose_pair(cx); - this.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.transact(window, cx, |this, window, cx| { + this.select_autoclose_pair(window, cx); + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { let line_mode = s.line_mode; s.move_with(|map, selection| { if selection.is_empty() && !line_mode { @@ -7661,18 +7994,19 @@ impl Editor { } }); }); - this.insert("", cx); + this.insert("", window, cx); }); } pub fn delete_to_previous_subword_start( &mut self, _: &DeleteToPreviousSubwordStart, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.transact(cx, |this, cx| { - this.select_autoclose_pair(cx); - this.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.transact(window, cx, |this, window, cx| { + this.select_autoclose_pair(window, cx); + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { let line_mode = s.line_mode; s.move_with(|map, selection| { if selection.is_empty() && !line_mode { @@ -7681,12 +8015,17 @@ impl Editor { } }); }); - this.insert("", cx); + this.insert("", window, cx); }); } - pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + pub fn move_to_next_word_end( + &mut self, + _: &MoveToNextWordEnd, + window: &mut Window, + cx: &mut Context, + ) { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_cursors_with(|map, head, _| { (movement::next_word_end(map, head), SelectionGoal::None) }); @@ -7696,17 +8035,23 @@ impl Editor { pub fn move_to_next_subword_end( &mut self, _: &MoveToNextSubwordEnd, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_cursors_with(|map, head, _| { (movement::next_subword_end(map, head), SelectionGoal::None) }); }) } - pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + pub fn select_to_next_word_end( + &mut self, + _: &SelectToNextWordEnd, + window: &mut Window, + cx: &mut Context, + ) { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_heads_with(|map, head, _| { (movement::next_word_end(map, head), SelectionGoal::None) }); @@ -7716,9 +8061,10 @@ impl Editor { pub fn select_to_next_subword_end( &mut self, _: &SelectToNextSubwordEnd, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_heads_with(|map, head, _| { (movement::next_subword_end(map, head), SelectionGoal::None) }); @@ -7728,10 +8074,11 @@ impl Editor { pub fn delete_to_next_word_end( &mut self, action: &DeleteToNextWordEnd, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.transact(cx, |this, cx| { - this.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.transact(window, cx, |this, window, cx| { + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { let line_mode = s.line_mode; s.move_with(|map, selection| { if selection.is_empty() && !line_mode { @@ -7744,17 +8091,18 @@ impl Editor { } }); }); - this.insert("", cx); + this.insert("", window, cx); }); } pub fn delete_to_next_subword_end( &mut self, _: &DeleteToNextSubwordEnd, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.transact(cx, |this, cx| { - this.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.transact(window, cx, |this, window, cx| { + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_with(|map, selection| { if selection.is_empty() { let cursor = movement::next_subword_end(map, selection.head()); @@ -7762,16 +8110,17 @@ impl Editor { } }); }); - this.insert("", cx); + this.insert("", window, cx); }); } pub fn move_to_beginning_of_line( &mut self, action: &MoveToBeginningOfLine, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_cursors_with(|map, head, _| { ( movement::indented_line_beginning(map, head, action.stop_at_soft_wraps), @@ -7784,9 +8133,10 @@ impl Editor { pub fn select_to_beginning_of_line( &mut self, action: &SelectToBeginningOfLine, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_heads_with(|map, head, _| { ( movement::indented_line_beginning(map, head, action.stop_at_soft_wraps), @@ -7799,10 +8149,11 @@ impl Editor { pub fn delete_to_beginning_of_line( &mut self, _: &DeleteToBeginningOfLine, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.transact(cx, |this, cx| { - this.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.transact(window, cx, |this, window, cx| { + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_with(|_, selection| { selection.reversed = true; }); @@ -7812,14 +8163,20 @@ impl Editor { &SelectToBeginningOfLine { stop_at_soft_wraps: false, }, + window, cx, ); - this.backspace(&Backspace, cx); + this.backspace(&Backspace, window, cx); }); } - pub fn move_to_end_of_line(&mut self, action: &MoveToEndOfLine, cx: &mut ViewContext) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + pub fn move_to_end_of_line( + &mut self, + action: &MoveToEndOfLine, + window: &mut Window, + cx: &mut Context, + ) { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_cursors_with(|map, head, _| { ( movement::line_end(map, head, action.stop_at_soft_wraps), @@ -7832,9 +8189,10 @@ impl Editor { pub fn select_to_end_of_line( &mut self, action: &SelectToEndOfLine, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_heads_with(|map, head, _| { ( movement::line_end(map, head, action.stop_at_soft_wraps), @@ -7844,41 +8202,54 @@ impl Editor { }) } - pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext) { - self.transact(cx, |this, cx| { + pub fn delete_to_end_of_line( + &mut self, + _: &DeleteToEndOfLine, + window: &mut Window, + cx: &mut Context, + ) { + self.transact(window, cx, |this, window, cx| { this.select_to_end_of_line( &SelectToEndOfLine { stop_at_soft_wraps: false, }, + window, cx, ); - this.delete(&Delete, cx); + this.delete(&Delete, window, cx); }); } - pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext) { - self.transact(cx, |this, cx| { + pub fn cut_to_end_of_line( + &mut self, + _: &CutToEndOfLine, + window: &mut Window, + cx: &mut Context, + ) { + self.transact(window, cx, |this, window, cx| { this.select_to_end_of_line( &SelectToEndOfLine { stop_at_soft_wraps: false, }, + window, cx, ); - this.cut(&Cut, cx); + this.cut(&Cut, window, cx); }); } pub fn move_to_start_of_paragraph( &mut self, _: &MoveToStartOfParagraph, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if matches!(self.mode, EditorMode::SingleLine { .. }) { cx.propagate(); return; } - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_with(|map, selection| { selection.collapse_to( movement::start_of_paragraph(map, selection.head(), 1), @@ -7891,14 +8262,15 @@ impl Editor { pub fn move_to_end_of_paragraph( &mut self, _: &MoveToEndOfParagraph, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if matches!(self.mode, EditorMode::SingleLine { .. }) { cx.propagate(); return; } - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_with(|map, selection| { selection.collapse_to( movement::end_of_paragraph(map, selection.head(), 1), @@ -7911,14 +8283,15 @@ impl Editor { pub fn select_to_start_of_paragraph( &mut self, _: &SelectToStartOfParagraph, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if matches!(self.mode, EditorMode::SingleLine { .. }) { cx.propagate(); return; } - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_heads_with(|map, head, _| { ( movement::start_of_paragraph(map, head, 1), @@ -7931,14 +8304,15 @@ impl Editor { pub fn select_to_end_of_paragraph( &mut self, _: &SelectToEndOfParagraph, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if matches!(self.mode, EditorMode::SingleLine { .. }) { cx.propagate(); return; } - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_heads_with(|map, head, _| { ( movement::end_of_paragraph(map, head, 1), @@ -7948,34 +8322,44 @@ impl Editor { }) } - pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext) { + pub fn move_to_beginning( + &mut self, + _: &MoveToBeginning, + window: &mut Window, + cx: &mut Context, + ) { if matches!(self.mode, EditorMode::SingleLine { .. }) { cx.propagate(); return; } - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select_ranges(vec![0..0]); }); } - pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext) { + pub fn select_to_beginning( + &mut self, + _: &SelectToBeginning, + window: &mut Window, + cx: &mut Context, + ) { let mut selection = self.selections.last::(cx); selection.set_head(Point::zero(), SelectionGoal::None); - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select(vec![selection]); }); } - pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext) { + pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context) { if matches!(self.mode, EditorMode::SingleLine { .. }) { cx.propagate(); return; } let cursor = self.buffer.read(cx).read(cx).len(); - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select_ranges(vec![cursor..cursor]) }); } @@ -7992,7 +8376,7 @@ impl Editor { &mut self, cursor_anchor: Anchor, new_position: Option, - cx: &mut ViewContext, + cx: &mut Context, ) { if let Some(nav_history) = self.nav_history.as_mut() { let buffer = self.buffer.read(cx).read(cx); @@ -8020,23 +8404,23 @@ impl Editor { } } - pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext) { + pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context) { let buffer = self.buffer.read(cx).snapshot(cx); let mut selection = self.selections.first::(cx); selection.set_head(buffer.len(), SelectionGoal::None); - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select(vec![selection]); }); } - pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext) { + pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context) { let end = self.buffer.read(cx).read(cx).len(); - self.change_selections(None, cx, |s| { + self.change_selections(None, window, cx, |s| { s.select_ranges(vec![0..end]); }); } - pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext) { + pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.selections.all::(cx); let max_point = display_map.buffer_snapshot.max_point(); @@ -8046,7 +8430,7 @@ impl Editor { selection.end = cmp::min(max_point, Point::new(rows.end.0, 0)); selection.reversed = false; } - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select(selections); }); } @@ -8054,7 +8438,8 @@ impl Editor { pub fn split_selection_into_lines( &mut self, _: &SplitSelectionIntoLines, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let mut to_unfold = Vec::new(); let mut new_selection_ranges = Vec::new(); @@ -8071,23 +8456,33 @@ impl Editor { } } self.unfold_ranges(&to_unfold, true, true, cx); - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select_ranges(new_selection_ranges); }); } - pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext) { - self.add_selection(true, cx); + pub fn add_selection_above( + &mut self, + _: &AddSelectionAbove, + window: &mut Window, + cx: &mut Context, + ) { + self.add_selection(true, window, cx); } - pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext) { - self.add_selection(false, cx); + pub fn add_selection_below( + &mut self, + _: &AddSelectionBelow, + window: &mut Window, + cx: &mut Context, + ) { + self.add_selection(false, window, cx); } - fn add_selection(&mut self, above: bool, cx: &mut ViewContext) { + fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.selections.all::(cx); - let text_layout_details = self.text_layout_details(cx); + let text_layout_details = self.text_layout_details(window); let mut state = self.add_selections_state.take().unwrap_or_else(|| { let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone(); let range = oldest_selection.display_range(&display_map).sorted(); @@ -8179,7 +8574,7 @@ impl Editor { state.stack.pop(); } - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select(new_selections); }); if state.stack.len() > 1 { @@ -8192,17 +8587,19 @@ impl Editor { display_map: &DisplaySnapshot, replace_newest: bool, autoscroll: Option, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Result<()> { fn select_next_match_ranges( this: &mut Editor, range: Range, replace_newest: bool, auto_scroll: Option, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { this.unfold_ranges(&[range.clone()], false, true, cx); - this.change_selections(auto_scroll, cx, |s| { + this.change_selections(auto_scroll, window, cx, |s| { if replace_newest { s.delete(s.newest_anchor().id); } @@ -8259,6 +8656,7 @@ impl Editor { next_selected_range, replace_newest, autoscroll, + window, cx, ); } else { @@ -8316,6 +8714,7 @@ impl Editor { selection.start..selection.end, replace_newest, autoscroll, + window, cx, ); } @@ -8343,7 +8742,13 @@ impl Editor { wordwise: false, done: false, }); - self.select_next_match_internal(display_map, replace_newest, autoscroll, cx)?; + self.select_next_match_internal( + display_map, + replace_newest, + autoscroll, + window, + cx, + )?; } } Ok(()) @@ -8352,12 +8757,13 @@ impl Editor { pub fn select_all_matches( &mut self, _action: &SelectAllMatches, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Result<()> { self.push_to_selection_history(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - self.select_next_match_internal(&display_map, false, None, cx)?; + self.select_next_match_internal(&display_map, false, None, window, cx)?; let Some(select_next_state) = self.select_next_state.as_mut() else { return Ok(()); }; @@ -8420,20 +8826,26 @@ impl Editor { false, cx, ); - self.change_selections(Some(Autoscroll::fit()), cx, |selections| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |selections| { selections.select(new_selections) }); Ok(()) } - pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext) -> Result<()> { + pub fn select_next( + &mut self, + action: &SelectNext, + window: &mut Window, + cx: &mut Context, + ) -> Result<()> { self.push_to_selection_history(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); self.select_next_match_internal( &display_map, action.replace_newest, Some(Autoscroll::newest()), + window, cx, )?; Ok(()) @@ -8442,7 +8854,8 @@ impl Editor { pub fn select_previous( &mut self, action: &SelectPrevious, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Result<()> { self.push_to_selection_history(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); @@ -8485,7 +8898,7 @@ impl Editor { if let Some(next_selected_range) = next_selected_range { self.unfold_ranges(&[next_selected_range.clone()], false, true, cx); - self.change_selections(Some(Autoscroll::newest()), cx, |s| { + self.change_selections(Some(Autoscroll::newest()), window, cx, |s| { if action.replace_newest { s.delete(s.newest_anchor().id); } @@ -8566,7 +8979,7 @@ impl Editor { true, cx, ); - self.change_selections(Some(Autoscroll::newest()), cx, |s| { + self.change_selections(Some(Autoscroll::newest()), window, cx, |s| { s.select(selections); }); } else if let Some(selected_text) = selected_text { @@ -8575,18 +8988,23 @@ impl Editor { wordwise: false, done: false, }); - self.select_previous(action, cx)?; + self.select_previous(action, window, cx)?; } } Ok(()) } - pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext) { + pub fn toggle_comments( + &mut self, + action: &ToggleComments, + window: &mut Window, + cx: &mut Context, + ) { if self.read_only(cx) { return; } - let text_layout_details = &self.text_layout_details(cx); - self.transact(cx, |this, cx| { + let text_layout_details = &self.text_layout_details(window); + self.transact(window, cx, |this, window, cx| { let mut selections = this.selections.all::(cx); let mut edits = Vec::new(); let mut selection_edit_ranges = Vec::new(); @@ -8839,7 +9257,9 @@ impl Editor { } drop(snapshot); - this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { + s.select(selections) + }); let selections = this.selections.all::(cx); let selections_on_single_row = selections.windows(2).all(|selections| { @@ -8858,7 +9278,7 @@ impl Editor { if advance_downwards { let snapshot = this.buffer.read(cx).snapshot(cx); - this.change_selections(Some(Autoscroll::fit()), cx, |s| { + this.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_cursors_with(|display_snapshot, display_point, _| { let mut point = display_point.to_point(display_snapshot); point.row += 1; @@ -8879,7 +9299,8 @@ impl Editor { pub fn select_enclosing_symbol( &mut self, _: &SelectEnclosingSymbol, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let buffer = self.buffer.read(cx).snapshot(cx); let old_selections = self.selections.all::(cx).into_boxed_slice(); @@ -8922,7 +9343,7 @@ impl Editor { .collect::>(); if selected_larger_symbol { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select(new_selections); }); } @@ -8931,7 +9352,8 @@ impl Editor { pub fn select_larger_syntax_node( &mut self, _: &SelectLargerSyntaxNode, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = self.buffer.read(cx).snapshot(cx); @@ -8980,7 +9402,7 @@ impl Editor { if selected_larger_node { stack.push(old_selections); - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select(new_selections); }); } @@ -8990,24 +9412,25 @@ impl Editor { pub fn select_smaller_syntax_node( &mut self, _: &SelectSmallerSyntaxNode, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let mut stack = mem::take(&mut self.select_larger_syntax_node_stack); if let Some(selections) = stack.pop() { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select(selections.to_vec()); }); } self.select_larger_syntax_node_stack = stack; } - fn refresh_runnables(&mut self, cx: &mut ViewContext) -> Task<()> { + fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context) -> Task<()> { if !EditorSettings::get_global(cx).gutter.runnables { self.clear_tasks(); return Task::ready(()); } - let project = self.project.as_ref().map(Model::downgrade); - cx.spawn(|this, mut cx| async move { + let project = self.project.as_ref().map(Entity::downgrade); + cx.spawn_in(window, |this, mut cx| async move { cx.background_executor().timer(UPDATE_DEBOUNCE).await; let Some(project) = project.and_then(|p| p.upgrade()) else { return; @@ -9036,8 +9459,8 @@ impl Editor { } }) .await; - let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone()); + let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone()); this.update(&mut cx, |this, _| { this.clear_tasks(); for (key, value) in rows { @@ -9055,7 +9478,7 @@ impl Editor { } fn runnable_rows( - project: Model, + project: Entity, snapshot: DisplaySnapshot, runnable_ranges: Vec, mut cx: AsyncWindowContext, @@ -9064,7 +9487,7 @@ impl Editor { .into_iter() .filter_map(|mut runnable| { let tasks = cx - .update(|cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx)) + .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx)) .ok()?; if tasks.is_empty() { return None; @@ -9096,9 +9519,9 @@ impl Editor { } fn templates_with_tags( - project: &Model, + project: &Entity, runnable: &mut Runnable, - cx: &WindowContext, + cx: &mut App, ) -> Vec<(TaskSourceKind, TaskTemplate)> { let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| { let (worktree_id, file) = project @@ -9154,9 +9577,10 @@ impl Editor { pub fn move_to_enclosing_bracket( &mut self, _: &MoveToEnclosingBracket, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.move_offsets_with(|snapshot, selection| { let Some(enclosing_bracket_ranges) = snapshot.enclosing_bracket_ranges(selection.start..selection.end) @@ -9210,11 +9634,18 @@ impl Editor { }); } - pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext) { - self.end_selection(cx); + pub fn undo_selection( + &mut self, + _: &UndoSelection, + window: &mut Window, + cx: &mut Context, + ) { + self.end_selection(window, cx); self.selection_history.mode = SelectionHistoryMode::Undoing; if let Some(entry) = self.selection_history.undo_stack.pop_back() { - self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec())); + self.change_selections(None, window, cx, |s| { + s.select_anchors(entry.selections.to_vec()) + }); self.select_next_state = entry.select_next_state; self.select_prev_state = entry.select_prev_state; self.add_selections_state = entry.add_selections_state; @@ -9223,11 +9654,18 @@ impl Editor { self.selection_history.mode = SelectionHistoryMode::Normal; } - pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext) { - self.end_selection(cx); + pub fn redo_selection( + &mut self, + _: &RedoSelection, + window: &mut Window, + cx: &mut Context, + ) { + self.end_selection(window, cx); self.selection_history.mode = SelectionHistoryMode::Redoing; if let Some(entry) = self.selection_history.redo_stack.pop_back() { - self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec())); + self.change_selections(None, window, cx, |s| { + s.select_anchors(entry.selections.to_vec()) + }); self.select_next_state = entry.select_next_state; self.select_prev_state = entry.select_prev_state; self.add_selections_state = entry.add_selections_state; @@ -9236,19 +9674,30 @@ impl Editor { self.selection_history.mode = SelectionHistoryMode::Normal; } - pub fn expand_excerpts(&mut self, action: &ExpandExcerpts, cx: &mut ViewContext) { + pub fn expand_excerpts( + &mut self, + action: &ExpandExcerpts, + _: &mut Window, + cx: &mut Context, + ) { self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx) } pub fn expand_excerpts_down( &mut self, action: &ExpandExcerptsDown, - cx: &mut ViewContext, + _: &mut Window, + cx: &mut Context, ) { self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx) } - pub fn expand_excerpts_up(&mut self, action: &ExpandExcerptsUp, cx: &mut ViewContext) { + pub fn expand_excerpts_up( + &mut self, + action: &ExpandExcerptsUp, + _: &mut Window, + cx: &mut Context, + ) { self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx) } @@ -9256,7 +9705,8 @@ impl Editor { &mut self, lines: u32, direction: ExpandExcerptDirection, - cx: &mut ViewContext, + + cx: &mut Context, ) { let selections = self.selections.disjoint_anchors(); @@ -9282,7 +9732,7 @@ impl Editor { &mut self, excerpt: ExcerptId, direction: ExpandExcerptDirection, - cx: &mut ViewContext, + cx: &mut Context, ) { let lines = EditorSettings::get_global(cx).expand_excerpt_lines; self.buffer.update(cx, |buffer, cx| { @@ -9290,14 +9740,20 @@ impl Editor { }) } - pub fn go_to_singleton_buffer_point(&mut self, point: Point, cx: &mut ViewContext) { - self.go_to_singleton_buffer_range(point..point, cx); + pub fn go_to_singleton_buffer_point( + &mut self, + point: Point, + window: &mut Window, + cx: &mut Context, + ) { + self.go_to_singleton_buffer_range(point..point, window, cx); } pub fn go_to_singleton_buffer_range( &mut self, range: Range, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let multibuffer = self.buffer().read(cx); let Some(buffer) = multibuffer.as_singleton() else { @@ -9309,20 +9765,35 @@ impl Editor { let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else { return; }; - self.change_selections(Some(Autoscroll::center()), cx, |s| { + self.change_selections(Some(Autoscroll::center()), window, cx, |s| { s.select_anchor_ranges([start..end]) }); } - fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext) { - self.go_to_diagnostic_impl(Direction::Next, cx) + fn go_to_diagnostic( + &mut self, + _: &GoToDiagnostic, + window: &mut Window, + cx: &mut Context, + ) { + self.go_to_diagnostic_impl(Direction::Next, window, cx) } - fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext) { - self.go_to_diagnostic_impl(Direction::Prev, cx) + fn go_to_prev_diagnostic( + &mut self, + _: &GoToPrevDiagnostic, + window: &mut Window, + cx: &mut Context, + ) { + self.go_to_diagnostic_impl(Direction::Prev, window, cx) } - pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext) { + pub fn go_to_diagnostic_impl( + &mut self, + direction: Direction, + window: &mut Window, + cx: &mut Context, + ) { let buffer = self.buffer.read(cx).snapshot(cx); let selection = self.selections.newest::(cx); @@ -9335,16 +9806,17 @@ impl Editor { self.activate_diagnostics( buffer_id, popover.local_diagnostic.diagnostic.group_id, + window, cx, ); if let Some(active_diagnostics) = self.active_diagnostics.as_ref() { let primary_range_start = active_diagnostics.primary_range.start; - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { let mut new_selection = s.newest_anchor().clone(); new_selection.collapse_to(primary_range_start, SelectionGoal::None); s.select_anchors(vec![new_selection.clone()]); }); - self.refresh_inline_completion(false, true, cx); + self.refresh_inline_completion(false, true, window, cx); } return; } @@ -9365,7 +9837,7 @@ impl Editor { } else { selection.head() }; - let snapshot = self.snapshot(cx); + let snapshot = self.snapshot(window, cx); loop { let mut diagnostics; if direction == Direction::Prev { @@ -9413,9 +9885,9 @@ impl Editor { let Some(buffer_id) = buffer.anchor_after(primary_range.start).buffer_id else { return; }; - self.activate_diagnostics(buffer_id, group_id, cx); + self.activate_diagnostics(buffer_id, group_id, window, cx); if self.active_diagnostics.is_some() { - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select(vec![Selection { id: selection.id, start: primary_range.start, @@ -9424,7 +9896,7 @@ impl Editor { goal: SelectionGoal::None, }]); }); - self.refresh_inline_completion(false, true, cx); + self.refresh_inline_completion(false, true, window, cx); } break; } else { @@ -9446,17 +9918,18 @@ impl Editor { } } - fn go_to_next_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext) { - let snapshot = self.snapshot(cx); + fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context) { + let snapshot = self.snapshot(window, cx); let selection = self.selections.newest::(cx); - self.go_to_hunk_after_position(&snapshot, selection.head(), cx); + self.go_to_hunk_after_position(&snapshot, selection.head(), window, cx); } fn go_to_hunk_after_position( &mut self, snapshot: &EditorSnapshot, position: Point, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Option { let mut hunk = snapshot .buffer_snapshot @@ -9471,7 +9944,7 @@ impl Editor { if let Some(hunk) = &hunk { let destination = Point::new(hunk.row_range.start.0, 0); self.unfold_ranges(&[destination..destination], false, false, cx); - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select_ranges(vec![destination..destination]); }); } @@ -9479,17 +9952,18 @@ impl Editor { hunk } - fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext) { - let snapshot = self.snapshot(cx); + fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, window: &mut Window, cx: &mut Context) { + let snapshot = self.snapshot(window, cx); let selection = self.selections.newest::(cx); - self.go_to_hunk_before_position(&snapshot, selection.head(), cx); + self.go_to_hunk_before_position(&snapshot, selection.head(), window, cx); } fn go_to_hunk_before_position( &mut self, snapshot: &EditorSnapshot, position: Point, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Option { let mut hunk = snapshot.buffer_snapshot.diff_hunk_before(position); if hunk.is_none() { @@ -9498,7 +9972,7 @@ impl Editor { if let Some(hunk) = &hunk { let destination = Point::new(hunk.row_range.start.0, 0); self.unfold_ranges(&[destination..destination], false, false, cx); - self.change_selections(Some(Autoscroll::fit()), cx, |s| { + self.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select_ranges(vec![destination..destination]); }); } @@ -9509,15 +9983,17 @@ impl Editor { pub fn go_to_definition( &mut self, _: &GoToDefinition, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { - let definition = self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, cx); - cx.spawn(|editor, mut cx| async move { + let definition = + self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx); + cx.spawn_in(window, |editor, mut cx| async move { if definition.await? == Navigated::Yes { return Ok(Navigated::Yes); } - match editor.update(&mut cx, |editor, cx| { - editor.find_all_references(&FindAllReferences, cx) + match editor.update_in(&mut cx, |editor, window, cx| { + editor.find_all_references(&FindAllReferences, window, cx) })? { Some(references) => references.await, None => Ok(Navigated::No), @@ -9528,64 +10004,72 @@ impl Editor { pub fn go_to_declaration( &mut self, _: &GoToDeclaration, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { - self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, cx) + self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx) } pub fn go_to_declaration_split( &mut self, _: &GoToDeclaration, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { - self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, cx) + self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx) } pub fn go_to_implementation( &mut self, _: &GoToImplementation, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { - self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, cx) + self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx) } pub fn go_to_implementation_split( &mut self, _: &GoToImplementationSplit, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { - self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, cx) + self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx) } pub fn go_to_type_definition( &mut self, _: &GoToTypeDefinition, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { - self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, cx) + self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx) } pub fn go_to_definition_split( &mut self, _: &GoToDefinitionSplit, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { - self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, cx) + self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx) } pub fn go_to_type_definition_split( &mut self, _: &GoToTypeDefinitionSplit, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { - self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, cx) + self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx) } fn go_to_definition_of_kind( &mut self, kind: GotoDefinitionKind, split: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { let Some(provider) = self.semantics_provider.clone() else { return Task::ready(Ok(Navigated::No)); @@ -9602,10 +10086,10 @@ impl Editor { return Task::ready(Ok(Navigated::No)); }; - cx.spawn(|editor, mut cx| async move { + cx.spawn_in(window, |editor, mut cx| async move { let definitions = definitions.await?; let navigated = editor - .update(&mut cx, |editor, cx| { + .update_in(&mut cx, |editor, window, cx| { editor.navigate_to_hover_links( Some(kind), definitions @@ -9616,6 +10100,7 @@ impl Editor { .map(HoverLink::Text) .collect::>(), split, + window, cx, ) })? @@ -9624,7 +10109,7 @@ impl Editor { }) } - pub fn open_url(&mut self, _: &OpenUrl, cx: &mut ViewContext) { + pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context) { let selection = self.selections.newest_anchor(); let head = selection.head(); let tail = selection.tail(); @@ -9644,7 +10129,7 @@ impl Editor { None }; - let url_finder = cx.spawn(|editor, mut cx| async move { + let url_finder = cx.spawn_in(window, |editor, mut cx| async move { let url = if let Some(end_pos) = end_position { find_url_from_range(&buffer, start_position..end_pos, cx.clone()) } else { @@ -9663,7 +10148,12 @@ impl Editor { url_finder.detach(); } - pub fn open_selected_filename(&mut self, _: &OpenSelectedFilename, cx: &mut ViewContext) { + pub fn open_selected_filename( + &mut self, + _: &OpenSelectedFilename, + window: &mut Window, + cx: &mut Context, + ) { let Some(workspace) = self.workspace() else { return; }; @@ -9678,13 +10168,13 @@ impl Editor { let project = self.project.clone(); - cx.spawn(|_, mut cx| async move { + cx.spawn_in(window, |_, mut cx| async move { let result = find_file(&buffer, project, buffer_position, &mut cx).await; if let Some((_, path)) = result { workspace - .update(&mut cx, |workspace, cx| { - workspace.open_resolved_path(path, cx) + .update_in(&mut cx, |workspace, window, cx| { + workspace.open_resolved_path(path, window, cx) })? .await?; } @@ -9698,7 +10188,8 @@ impl Editor { kind: Option, mut definitions: Vec, split: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { // If there is one definition, just open it directly if definitions.len() == 1 { @@ -9714,7 +10205,8 @@ impl Editor { Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target)))) } HoverLink::InlayHint(lsp_location, server_id) => { - let computation = self.compute_target_location(lsp_location, server_id, cx); + let computation = + self.compute_target_location(lsp_location, server_id, window, cx); cx.background_executor().spawn(async move { let location = computation.await?; Ok(TargetTaskResult::Location(location)) @@ -9726,10 +10218,10 @@ impl Editor { } HoverLink::File(path) => { if let Some(workspace) = self.workspace() { - cx.spawn(|_, mut cx| async move { + cx.spawn_in(window, |_, mut cx| async move { workspace - .update(&mut cx, |workspace, cx| { - workspace.open_resolved_path(path, cx) + .update_in(&mut cx, |workspace, window, cx| { + workspace.open_resolved_path(path, window, cx) })? .await .map(|_| TargetTaskResult::AlreadyNavigated) @@ -9739,14 +10231,14 @@ impl Editor { } } }; - cx.spawn(|editor, mut cx| async move { + cx.spawn_in(window, |editor, mut cx| async move { let target = match target_task.await.context("target resolution task")? { TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes), TargetTaskResult::Location(None) => return Ok(Navigated::No), TargetTaskResult::Location(Some(target)) => target, }; - editor.update(&mut cx, |editor, cx| { + editor.update_in(&mut cx, |editor, window, cx| { let Some(workspace) = editor.workspace() else { return Navigated::No; }; @@ -9757,13 +10249,13 @@ impl Editor { let range = collapse_multiline_range(range); if Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref() { - editor.go_to_singleton_buffer_range(range.clone(), cx); + editor.go_to_singleton_buffer_range(range.clone(), window, cx); } else { - cx.window_context().defer(move |cx| { - let target_editor: View = + window.defer(cx, move |window, cx| { + let target_editor: Entity = workspace.update(cx, |workspace, cx| { let pane = if split { - workspace.adjacent_pane(cx) + workspace.adjacent_pane(window, cx) } else { workspace.active_pane().clone() }; @@ -9773,6 +10265,7 @@ impl Editor { target.buffer.clone(), true, true, + window, cx, ) }); @@ -9780,7 +10273,7 @@ impl Editor { // When selecting a definition in a different buffer, disable the nav history // to avoid creating a history entry at the previous cursor location. pane.update(cx, |pane, _| pane.disable_history()); - target_editor.go_to_singleton_buffer_range(range, cx); + target_editor.go_to_singleton_buffer_range(range, window, cx); pane.update(cx, |pane, _| pane.enable_history()); }); }); @@ -9789,9 +10282,9 @@ impl Editor { }) }) } else if !definitions.is_empty() { - cx.spawn(|editor, mut cx| async move { + cx.spawn_in(window, |editor, mut cx| async move { let (title, location_tasks, workspace) = editor - .update(&mut cx, |editor, cx| { + .update_in(&mut cx, |editor, window, cx| { let tab_kind = match kind { Some(GotoDefinitionKind::Implementation) => "Implementations", _ => "Definitions", @@ -9818,9 +10311,8 @@ impl Editor { .into_iter() .map(|definition| match definition { HoverLink::Text(link) => Task::ready(Ok(Some(link.target))), - HoverLink::InlayHint(lsp_location, server_id) => { - editor.compute_target_location(lsp_location, server_id, cx) - } + HoverLink::InlayHint(lsp_location, server_id) => editor + .compute_target_location(lsp_location, server_id, window, cx), HoverLink::Url(_) => Task::ready(Ok(None)), HoverLink::File(_) => Task::ready(Ok(None)), }) @@ -9840,13 +10332,14 @@ impl Editor { return Ok(Navigated::No); }; let opened = workspace - .update(&mut cx, |workspace, cx| { + .update_in(&mut cx, |workspace, window, cx| { Self::open_locations_in_multibuffer( workspace, locations, title, split, MultibufferSelectionMode::First, + window, cx, ) }) @@ -9863,13 +10356,14 @@ impl Editor { &self, lsp_location: lsp::Location, server_id: LanguageServerId, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task>> { let Some(project) = self.project.clone() else { return Task::ready(Ok(None)); }; - cx.spawn(move |editor, mut cx| async move { + cx.spawn_in(window, move |editor, mut cx| async move { let location_task = editor.update(&mut cx, |_, cx| { project.update(cx, |project, cx| { let language_server_name = project @@ -9911,7 +10405,8 @@ impl Editor { pub fn find_all_references( &mut self, _: &FindAllReferences, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Option>> { let selection = self.selections.newest::(cx); let multi_buffer = self.buffer.read(cx); @@ -9946,7 +10441,7 @@ impl Editor { let workspace = self.workspace()?; let project = workspace.read(cx).project().clone(); let references = project.update(cx, |project, cx| project.references(&buffer, head, cx)); - Some(cx.spawn(|editor, mut cx| async move { + Some(cx.spawn_in(window, |editor, mut cx| async move { let _cleanup = defer({ let mut cx = cx.clone(); move || { @@ -9969,7 +10464,7 @@ impl Editor { return anyhow::Ok(Navigated::No); } - workspace.update(&mut cx, |workspace, cx| { + workspace.update_in(&mut cx, |workspace, window, cx| { let title = locations .first() .as_ref() @@ -9989,6 +10484,7 @@ impl Editor { title, false, MultibufferSelectionMode::First, + window, cx, ); Navigated::Yes @@ -10003,7 +10499,8 @@ impl Editor { title: String, split: bool, multibuffer_selection_mode: MultibufferSelectionMode, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { // If there are multiple definitions, open them in a multibuffer locations.sort_by_key(|location| location.buffer.read(cx).remote_id()); @@ -10011,7 +10508,7 @@ impl Editor { let mut ranges = Vec::new(); let capability = workspace.project().read(cx).capability(); - let excerpt_buffer = cx.new_model(|cx| { + let excerpt_buffer = cx.new(|cx| { let mut multibuffer = MultiBuffer::new(capability); while let Some(location) = locations.next() { let buffer = location.buffer.read(cx); @@ -10040,14 +10537,20 @@ impl Editor { multibuffer.with_title(title) }); - let editor = cx.new_view(|cx| { - Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), true, cx) + let editor = cx.new(|cx| { + Editor::for_multibuffer( + excerpt_buffer, + Some(workspace.project().clone()), + true, + window, + cx, + ) }); editor.update(cx, |editor, cx| { match multibuffer_selection_mode { MultibufferSelectionMode::First => { if let Some(first_range) = ranges.first() { - editor.change_selections(None, cx, |selections| { + editor.change_selections(None, window, cx, |selections| { selections.clear_disjoint(); selections.select_anchor_ranges(std::iter::once(first_range.clone())); }); @@ -10059,7 +10562,7 @@ impl Editor { ); } MultibufferSelectionMode::All => { - editor.change_selections(None, cx, |selections| { + editor.change_selections(None, window, cx, |selections| { selections.clear_disjoint(); selections.select_anchor_ranges(ranges); }); @@ -10072,23 +10575,28 @@ impl Editor { let item_id = item.item_id(); if split { - workspace.split_item(SplitDirection::Right, item.clone(), cx); + workspace.split_item(SplitDirection::Right, item.clone(), window, cx); } else { let destination_index = workspace.active_pane().update(cx, |pane, cx| { if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation { - pane.close_current_preview_item(cx) + pane.close_current_preview_item(window, cx) } else { None } }); - workspace.add_item_to_active_pane(item.clone(), destination_index, true, cx); + workspace.add_item_to_active_pane(item.clone(), destination_index, true, window, cx); } workspace.active_pane().update(cx, |pane, cx| { pane.set_preview_item_id(Some(item_id), cx); }); } - pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext) -> Option>> { + pub fn rename( + &mut self, + _: &Rename, + window: &mut Window, + cx: &mut Context, + ) -> Option>> { use language::ToOffset as _; let provider = self.semantics_provider.clone()?; @@ -10113,7 +10621,7 @@ impl Editor { .unwrap_or_else(|| Task::ready(Ok(None))); drop(snapshot); - Some(cx.spawn(|this, mut cx| async move { + Some(cx.spawn_in(window, |this, mut cx| async move { let rename_range = if let Some(range) = prepare_rename.await? { Some(range) } else { @@ -10131,7 +10639,7 @@ impl Editor { })? }; if let Some(rename_range) = rename_range { - this.update(&mut cx, |this, cx| { + this.update_in(&mut cx, |this, window, cx| { let snapshot = cursor_buffer.read(cx).snapshot(); let rename_buffer_range = rename_range.to_offset(&snapshot); let cursor_offset_in_rename_range = @@ -10139,7 +10647,7 @@ impl Editor { let cursor_offset_in_rename_range_end = cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start); - this.take_rename(false, cx); + this.take_rename(false, window, cx); let buffer = this.buffer.read(cx).read(cx); let cursor_offset = selection.head().to_offset(&buffer); let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range); @@ -10161,8 +10669,8 @@ impl Editor { // Position the selection in the rename editor so that it matches the current selection. this.show_local_selections = false; - let rename_editor = cx.new_view(|cx| { - let mut editor = Editor::single_line(cx); + let rename_editor = cx.new(|cx| { + let mut editor = Editor::single_line(window, cx); editor.buffer.update(cx, |buffer, cx| { buffer.edit([(0..0, old_name.clone())], None, cx) }); @@ -10170,7 +10678,7 @@ impl Editor { .cmp(&cursor_offset_in_rename_range_end) { Ordering::Equal => { - editor.select_all(&SelectAll, cx); + editor.select_all(&SelectAll, window, cx); return editor; } Ordering::Less => { @@ -10181,9 +10689,9 @@ impl Editor { } }; if rename_selection_range.end > old_name.len() { - editor.select_all(&SelectAll, cx); + editor.select_all(&SelectAll, window, cx); } else { - editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| { s.select_ranges([rename_selection_range]); }); } @@ -10216,7 +10724,7 @@ impl Editor { cx, ); let rename_focus_handle = rename_editor.focus_handle(cx); - cx.focus(&rename_focus_handle); + window.focus(&rename_focus_handle); let block_id = this.insert_blocks( [BlockProperties { style: BlockStyle::Flex, @@ -10245,10 +10753,10 @@ impl Editor { status: cx.editor_style.status.clone(), inlay_hints_style: HighlightStyle { font_weight: Some(FontWeight::BOLD), - ..make_inlay_hints_style(cx) + ..make_inlay_hints_style(cx.app) }, inline_completion_styles: make_suggestion_styles( - cx, + cx.app, ), ..EditorStyle::default() }, @@ -10277,9 +10785,10 @@ impl Editor { pub fn confirm_rename( &mut self, _: &ConfirmRename, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Option>> { - let rename = self.take_rename(false, cx)?; + let rename = self.take_rename(false, window, cx)?; let workspace = self.workspace()?.downgrade(); let (buffer, start) = self .buffer @@ -10303,7 +10812,7 @@ impl Editor { cx, )?; - Some(cx.spawn(|editor, mut cx| async move { + Some(cx.spawn_in(window, |editor, mut cx| async move { let project_transaction = rename.await?; Self::open_project_transaction( &editor, @@ -10324,11 +10833,12 @@ impl Editor { fn take_rename( &mut self, moving_cursor: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Option { let rename = self.pending_rename.take()?; - if rename.editor.focus_handle(cx).is_focused(cx) { - cx.focus(&self.focus_handle); + if rename.editor.focus_handle(cx).is_focused(window) { + window.focus(&self.focus_handle); } self.remove_blocks( @@ -10353,7 +10863,7 @@ impl Editor { .min(rename_range.end); drop(snapshot); - self.change_selections(None, cx, |s| { + self.change_selections(None, window, cx, |s| { s.select_ranges(vec![cursor_in_editor..cursor_in_editor]) }); } else { @@ -10367,19 +10877,31 @@ impl Editor { self.pending_rename.as_ref() } - fn format(&mut self, _: &Format, cx: &mut ViewContext) -> Option>> { + fn format( + &mut self, + _: &Format, + window: &mut Window, + cx: &mut Context, + ) -> Option>> { let project = match &self.project { Some(project) => project.clone(), None => return None, }; - Some(self.perform_format(project, FormatTrigger::Manual, FormatTarget::Buffers, cx)) + Some(self.perform_format( + project, + FormatTrigger::Manual, + FormatTarget::Buffers, + window, + cx, + )) } fn format_selections( &mut self, _: &FormatSelections, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Option>> { let project = match &self.project { Some(project) => project.clone(), @@ -10397,16 +10919,18 @@ impl Editor { project, FormatTrigger::Manual, FormatTarget::Ranges(ranges), + window, cx, )) } fn perform_format( &mut self, - project: Model, + project: Entity, trigger: FormatTrigger, target: FormatTarget, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task> { let buffer = self.buffer.clone(); let (buffers, target) = match target { @@ -10446,7 +10970,7 @@ impl Editor { project.format(buffers, target, true, trigger, cx) }); - cx.spawn(|_, mut cx| async move { + cx.spawn_in(window, |_, mut cx| async move { let transaction = futures::select_biased! { () = timeout => { log::warn!("timed out waiting for formatting"); @@ -10471,7 +10995,12 @@ impl Editor { }) } - fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext) { + fn restart_language_server( + &mut self, + _: &RestartLanguageServer, + _: &mut Window, + cx: &mut Context, + ) { if let Some(project) = self.project.clone() { self.buffer.update(cx, |multi_buffer, cx| { project.update(cx, |project, cx| { @@ -10484,7 +11013,8 @@ impl Editor { fn cancel_language_server_work( &mut self, _: &actions::CancelLanguageServerWork, - cx: &mut ViewContext, + _: &mut Window, + cx: &mut Context, ) { if let Some(project) = self.project.clone() { self.buffer.update(cx, |multi_buffer, cx| { @@ -10495,11 +11025,16 @@ impl Editor { } } - fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext) { - cx.show_character_palette(); + fn show_character_palette( + &mut self, + _: &ShowCharacterPalette, + window: &mut Window, + _: &mut Context, + ) { + window.show_character_palette(); } - fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext) { + fn refresh_active_diagnostics(&mut self, cx: &mut Context) { if let Some(active_diagnostics) = self.active_diagnostics.as_mut() { let buffer = self.buffer.read(cx).snapshot(cx); let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer); @@ -10532,10 +11067,11 @@ impl Editor { &mut self, buffer_id: BufferId, group_id: usize, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { self.dismiss_diagnostics(cx); - let snapshot = self.snapshot(cx); + let snapshot = self.snapshot(window, cx); self.active_diagnostics = self.display_map.update(cx, |display_map, cx| { let buffer = self.buffer.read(cx).snapshot(cx); @@ -10594,7 +11130,7 @@ impl Editor { }); } - fn dismiss_diagnostics(&mut self, cx: &mut ViewContext) { + fn dismiss_diagnostics(&mut self, cx: &mut Context) { if let Some(active_diagnostic_group) = self.active_diagnostics.take() { self.display_map.update(cx, |display_map, cx| { display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx); @@ -10607,7 +11143,8 @@ impl Editor { &mut self, selections: Vec>, pending_selection: Option>, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let old_cursor_position = self.selections.newest_anchor().head(); self.selections.change_with(cx, |s| { @@ -10618,7 +11155,7 @@ impl Editor { s.clear_pending(); } }); - self.selections_did_change(false, &old_cursor_position, true, cx); + self.selections_did_change(false, &old_cursor_position, true, window, cx); } fn push_to_selection_history(&mut self) { @@ -10632,16 +11169,22 @@ impl Editor { pub fn transact( &mut self, - cx: &mut ViewContext, - update: impl FnOnce(&mut Self, &mut ViewContext), + window: &mut Window, + cx: &mut Context, + update: impl FnOnce(&mut Self, &mut Window, &mut Context), ) -> Option { - self.start_transaction_at(Instant::now(), cx); - update(self, cx); + self.start_transaction_at(Instant::now(), window, cx); + update(self, window, cx); self.end_transaction_at(Instant::now(), cx) } - pub fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext) { - self.end_selection(cx); + pub fn start_transaction_at( + &mut self, + now: Instant, + window: &mut Window, + cx: &mut Context, + ) { + self.end_selection(window, cx); if let Some(tx_id) = self .buffer .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx)) @@ -10657,7 +11200,7 @@ impl Editor { pub fn end_transaction_at( &mut self, now: Instant, - cx: &mut ViewContext, + cx: &mut Context, ) -> Option { if let Some(transaction_id) = self .buffer @@ -10678,9 +11221,9 @@ impl Editor { } } - pub fn set_mark(&mut self, _: &actions::SetMark, cx: &mut ViewContext) { + pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context) { if self.selection_mark_mode { - self.change_selections(None, cx, |s| { + self.change_selections(None, window, cx, |s| { s.move_with(|_, sel| { sel.collapse_to(sel.head(), SelectionGoal::None); }); @@ -10693,9 +11236,10 @@ impl Editor { pub fn swap_selection_ends( &mut self, _: &actions::SwapSelectionEnds, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.change_selections(None, cx, |s| { + self.change_selections(None, window, cx, |s| { s.move_with(|_, sel| { if sel.start != sel.end { sel.reversed = !sel.reversed @@ -10706,7 +11250,12 @@ impl Editor { cx.notify(); } - pub fn toggle_fold(&mut self, _: &actions::ToggleFold, cx: &mut ViewContext) { + pub fn toggle_fold( + &mut self, + _: &actions::ToggleFold, + window: &mut Window, + cx: &mut Context, + ) { if self.is_singleton(cx) { let selection = self.selections.newest::(cx); @@ -10721,9 +11270,9 @@ impl Editor { selection.range() }; if display_map.folds_in_range(range).next().is_some() { - self.unfold_lines(&Default::default(), cx) + self.unfold_lines(&Default::default(), window, cx) } else { - self.fold(&Default::default(), cx) + self.fold(&Default::default(), window, cx) } } else { let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx); @@ -10745,7 +11294,8 @@ impl Editor { pub fn toggle_fold_recursive( &mut self, _: &actions::ToggleFoldRecursive, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let selection = self.selections.newest::(cx); @@ -10760,13 +11310,13 @@ impl Editor { selection.range() }; if display_map.folds_in_range(range).next().is_some() { - self.unfold_recursive(&Default::default(), cx) + self.unfold_recursive(&Default::default(), window, cx) } else { - self.fold_recursive(&Default::default(), cx) + self.fold_recursive(&Default::default(), window, cx) } } - pub fn fold(&mut self, _: &actions::Fold, cx: &mut ViewContext) { + pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context) { if self.is_singleton(cx) { let mut to_fold = Vec::new(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); @@ -10806,7 +11356,7 @@ impl Editor { } } - self.fold_creases(to_fold, true, cx); + self.fold_creases(to_fold, true, window, cx); } else { let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx); @@ -10820,7 +11370,12 @@ impl Editor { } } - fn fold_at_level(&mut self, fold_at: &FoldAtLevel, cx: &mut ViewContext) { + fn fold_at_level( + &mut self, + fold_at: &FoldAtLevel, + window: &mut Window, + cx: &mut Context, + ) { if !self.buffer.read(cx).is_singleton() { return; } @@ -10833,7 +11388,7 @@ impl Editor { while let Some((mut start_row, end_row, current_level)) = stack.pop() { while start_row < end_row { match self - .snapshot(cx) + .snapshot(window, cx) .crease_for_buffer_row(MultiBufferRow(start_row)) { Some(crease) => { @@ -10853,27 +11408,28 @@ impl Editor { } } - self.fold_creases(to_fold, true, cx); + self.fold_creases(to_fold, true, window, cx); } - pub fn fold_all(&mut self, _: &actions::FoldAll, cx: &mut ViewContext) { + pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context) { if self.buffer.read(cx).is_singleton() { let mut fold_ranges = Vec::new(); let snapshot = self.buffer.read(cx).snapshot(cx); for row in 0..snapshot.max_row().0 { - if let Some(foldable_range) = - self.snapshot(cx).crease_for_buffer_row(MultiBufferRow(row)) + if let Some(foldable_range) = self + .snapshot(window, cx) + .crease_for_buffer_row(MultiBufferRow(row)) { fold_ranges.push(foldable_range); } } - self.fold_creases(fold_ranges, true, cx); + self.fold_creases(fold_ranges, true, window, cx); } else { - self.toggle_fold_multiple_buffers = cx.spawn(|editor, mut cx| async move { + self.toggle_fold_multiple_buffers = cx.spawn_in(window, |editor, mut cx| async move { editor - .update(&mut cx, |editor, cx| { + .update_in(&mut cx, |editor, _, cx| { for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() { editor.fold_buffer(buffer_id, cx); } @@ -10886,7 +11442,8 @@ impl Editor { pub fn fold_function_bodies( &mut self, _: &actions::FoldFunctionBodies, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let snapshot = self.buffer.read(cx).snapshot(cx); @@ -10900,10 +11457,15 @@ impl Editor { .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone())) .collect(); - self.fold_creases(creases, true, cx); + self.fold_creases(creases, true, window, cx); } - pub fn fold_recursive(&mut self, _: &actions::FoldRecursive, cx: &mut ViewContext) { + pub fn fold_recursive( + &mut self, + _: &actions::FoldRecursive, + window: &mut Window, + cx: &mut Context, + ) { let mut to_fold = Vec::new(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let selections = self.selections.all_adjusted(cx); @@ -10936,10 +11498,10 @@ impl Editor { } } - self.fold_creases(to_fold, true, cx); + self.fold_creases(to_fold, true, window, cx); } - pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext) { + pub fn fold_at(&mut self, fold_at: &FoldAt, window: &mut Window, cx: &mut Context) { let buffer_row = fold_at.buffer_row; let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); @@ -10950,11 +11512,11 @@ impl Editor { .iter() .any(|selection| crease.range().overlaps(&selection.range())); - self.fold_creases(vec![crease], autoscroll, cx); + self.fold_creases(vec![crease], autoscroll, window, cx); } } - pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext) { + pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context) { if self.is_singleton(cx) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = &display_map.buffer_snapshot; @@ -10984,7 +11546,12 @@ impl Editor { } } - pub fn unfold_recursive(&mut self, _: &UnfoldRecursive, cx: &mut ViewContext) { + pub fn unfold_recursive( + &mut self, + _: &UnfoldRecursive, + _window: &mut Window, + cx: &mut Context, + ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let selections = self.selections.all::(cx); let ranges = selections @@ -11002,7 +11569,12 @@ impl Editor { self.unfold_ranges(&ranges, true, true, cx); } - pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext) { + pub fn unfold_at( + &mut self, + unfold_at: &UnfoldAt, + _window: &mut Window, + cx: &mut Context, + ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let intersection_range = Point::new(unfold_at.buffer_row.0, 0) @@ -11017,10 +11589,15 @@ impl Editor { .iter() .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range)); - self.unfold_ranges(&[intersection_range], true, autoscroll, cx) + self.unfold_ranges(&[intersection_range], true, autoscroll, cx); } - pub fn unfold_all(&mut self, _: &actions::UnfoldAll, cx: &mut ViewContext) { + pub fn unfold_all( + &mut self, + _: &actions::UnfoldAll, + _window: &mut Window, + cx: &mut Context, + ) { if self.buffer.read(cx).is_singleton() { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx); @@ -11037,7 +11614,12 @@ impl Editor { } } - pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext) { + pub fn fold_selected_ranges( + &mut self, + _: &FoldSelectedRanges, + window: &mut Window, + cx: &mut Context, + ) { let selections = self.selections.all::(cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let line_mode = self.selections.line_mode; @@ -11058,28 +11640,30 @@ impl Editor { } }) .collect::>(); - self.fold_creases(ranges, true, cx); + self.fold_creases(ranges, true, window, cx); } pub fn fold_ranges( &mut self, ranges: Vec>, auto_scroll: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let ranges = ranges .into_iter() .map(|r| Crease::simple(r, display_map.fold_placeholder.clone())) .collect::>(); - self.fold_creases(ranges, auto_scroll, cx); + self.fold_creases(ranges, auto_scroll, window, cx); } pub fn fold_creases( &mut self, creases: Vec>, auto_scroll: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if creases.is_empty() { return; @@ -11105,7 +11689,7 @@ impl Editor { if let Some(active_diagnostics) = self.active_diagnostics.take() { // Clear diagnostics block when folding a range that contains it. - let snapshot = self.snapshot(cx); + let snapshot = self.snapshot(window, cx); if snapshot.intersects_fold(active_diagnostics.primary_range.start) { drop(snapshot); self.active_diagnostics = Some(active_diagnostics); @@ -11124,14 +11708,14 @@ impl Editor { ranges: &[Range], inclusive: bool, auto_scroll: bool, - cx: &mut ViewContext, + cx: &mut Context, ) { self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| { map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx) }); } - pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut ViewContext) { + pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context) { if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) { return; } @@ -11148,7 +11732,7 @@ impl Editor { cx.notify(); } - pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut ViewContext) { + pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context) { if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) { return; } @@ -11166,11 +11750,11 @@ impl Editor { cx.notify(); } - pub fn is_buffer_folded(&self, buffer: BufferId, cx: &AppContext) -> bool { + pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool { self.display_map.read(cx).is_buffer_folded(buffer) } - pub fn folded_buffers<'a>(&self, cx: &'a AppContext) -> &'a HashSet { + pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet { self.display_map.read(cx).folded_buffers() } @@ -11180,7 +11764,7 @@ impl Editor { ranges: &[Range], type_id: TypeId, auto_scroll: bool, - cx: &mut ViewContext, + cx: &mut Context, ) { self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| { map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx) @@ -11191,8 +11775,8 @@ impl Editor { &mut self, ranges: &[Range], auto_scroll: bool, - cx: &mut ViewContext, - update: impl FnOnce(&mut DisplayMap, &mut ModelContext), + cx: &mut Context, + update: impl FnOnce(&mut DisplayMap, &mut Context), ) { if ranges.is_empty() { return; @@ -11217,17 +11801,22 @@ impl Editor { self.active_indent_guides_state.dirty = true; } - pub fn default_fold_placeholder(&self, cx: &AppContext) -> FoldPlaceholder { + pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder { self.display_map.read(cx).fold_placeholder.clone() } - pub fn set_expand_all_diff_hunks(&mut self, cx: &mut AppContext) { + pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) { self.buffer.update(cx, |buffer, cx| { buffer.set_all_diff_hunks_expanded(cx); }); } - pub fn expand_all_diff_hunks(&mut self, _: &ExpandAllHunkDiffs, cx: &mut ViewContext) { + pub fn expand_all_diff_hunks( + &mut self, + _: &ExpandAllHunkDiffs, + _window: &mut Window, + cx: &mut Context, + ) { self.buffer.update(cx, |buffer, cx| { buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx) }); @@ -11236,19 +11825,20 @@ impl Editor { pub fn toggle_selected_diff_hunks( &mut self, _: &ToggleSelectedDiffHunks, - cx: &mut ViewContext, + _window: &mut Window, + cx: &mut Context, ) { let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect(); self.toggle_diff_hunks_in_ranges(ranges, cx); } - pub fn expand_selected_diff_hunks(&mut self, cx: &mut ViewContext) { + pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context) { let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect(); self.buffer .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx)) } - pub fn clear_expanded_diff_hunks(&mut self, cx: &mut ViewContext) -> bool { + pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context) -> bool { self.buffer.update(cx, |buffer, cx| { let ranges = vec![Anchor::min()..Anchor::max()]; if !buffer.all_diff_hunks_expanded() @@ -11265,7 +11855,7 @@ impl Editor { fn toggle_diff_hunks_in_ranges( &mut self, ranges: Vec>, - cx: &mut ViewContext<'_, Editor>, + cx: &mut Context<'_, Editor>, ) { self.buffer.update(cx, |buffer, cx| { if buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx) { @@ -11279,7 +11869,8 @@ impl Editor { pub(crate) fn apply_all_diff_hunks( &mut self, _: &ApplyAllDiffHunks, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let buffers = self.buffer.read(cx).all_buffers(); for branch_buffer in buffers { @@ -11289,19 +11880,20 @@ impl Editor { } if let Some(project) = self.project.clone() { - self.save(true, project, cx).detach_and_log_err(cx); + self.save(true, project, window, cx).detach_and_log_err(cx); } } pub(crate) fn apply_selected_diff_hunks( &mut self, _: &ApplyDiffHunk, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - let snapshot = self.snapshot(cx); + let snapshot = self.snapshot(window, cx); let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx).into_iter()); let mut ranges_by_buffer = HashMap::default(); - self.transact(cx, |editor, cx| { + self.transact(window, cx, |editor, _window, cx| { for hunk in hunks { if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) { ranges_by_buffer @@ -11319,11 +11911,11 @@ impl Editor { }); if let Some(project) = self.project.clone() { - self.save(true, project, cx).detach_and_log_err(cx); + self.save(true, project, window, cx).detach_and_log_err(cx); } } - pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut ViewContext) { + pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context) { if hovered != self.gutter_hovered { self.gutter_hovered = hovered; cx.notify(); @@ -11334,7 +11926,7 @@ impl Editor { &mut self, blocks: impl IntoIterator>, autoscroll: Option, - cx: &mut ViewContext, + cx: &mut Context, ) -> Vec { let blocks = self .display_map @@ -11350,7 +11942,7 @@ impl Editor { &mut self, heights: HashMap, autoscroll: Option, - cx: &mut ViewContext, + cx: &mut Context, ) { self.display_map .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx)); @@ -11364,7 +11956,7 @@ impl Editor { &mut self, renderers: HashMap, autoscroll: Option, - cx: &mut ViewContext, + cx: &mut Context, ) { self.display_map .update(cx, |display_map, _cx| display_map.replace_blocks(renderers)); @@ -11378,7 +11970,7 @@ impl Editor { &mut self, block_ids: HashSet, autoscroll: Option, - cx: &mut ViewContext, + cx: &mut Context, ) { self.display_map.update(cx, |display_map, cx| { display_map.remove_blocks(block_ids, cx) @@ -11392,7 +11984,7 @@ impl Editor { pub fn row_for_block( &self, block_id: CustomBlockId, - cx: &mut ViewContext, + cx: &mut Context, ) -> Option { self.display_map .update(cx, |map, cx| map.row_for_block(block_id, cx)) @@ -11409,7 +12001,7 @@ impl Editor { pub fn insert_creases( &mut self, creases: impl IntoIterator>, - cx: &mut ViewContext, + cx: &mut Context, ) -> Vec { self.display_map .update(cx, |map, cx| map.insert_creases(creases, cx)) @@ -11418,29 +12010,29 @@ impl Editor { pub fn remove_creases( &mut self, ids: impl IntoIterator, - cx: &mut ViewContext, + cx: &mut Context, ) { self.display_map .update(cx, |map, cx| map.remove_creases(ids, cx)); } - pub fn longest_row(&self, cx: &mut AppContext) -> DisplayRow { + pub fn longest_row(&self, cx: &mut App) -> DisplayRow { self.display_map .update(cx, |map, cx| map.snapshot(cx)) .longest_row() } - pub fn max_point(&self, cx: &mut AppContext) -> DisplayPoint { + pub fn max_point(&self, cx: &mut App) -> DisplayPoint { self.display_map .update(cx, |map, cx| map.snapshot(cx)) .max_point() } - pub fn text(&self, cx: &AppContext) -> String { + pub fn text(&self, cx: &App) -> String { self.buffer.read(cx).read(cx).text() } - pub fn text_option(&self, cx: &AppContext) -> Option { + pub fn text_option(&self, cx: &App) -> Option { let text = self.text(cx); let text = text.trim(); @@ -11451,8 +12043,13 @@ impl Editor { Some(text.to_string()) } - pub fn set_text(&mut self, text: impl Into>, cx: &mut ViewContext) { - self.transact(cx, |this, cx| { + pub fn set_text( + &mut self, + text: impl Into>, + window: &mut Window, + cx: &mut Context, + ) { + self.transact(window, cx, |this, _, cx| { this.buffer .read(cx) .as_singleton() @@ -11461,13 +12058,13 @@ impl Editor { }); } - pub fn display_text(&self, cx: &mut AppContext) -> String { + pub fn display_text(&self, cx: &mut App) -> String { self.display_map .update(cx, |map, cx| map.snapshot(cx)) .text() } - pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> { + pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> { let mut wrap_guides = smallvec::smallvec![]; if self.show_wrap_guides == Some(false) { @@ -11487,7 +12084,7 @@ impl Editor { wrap_guides } - pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap { + pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap { let settings = self.buffer.read(cx).settings_at(0, cx); let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap); match mode { @@ -11507,7 +12104,8 @@ impl Editor { pub fn set_soft_wrap_mode( &mut self, mode: language_settings::SoftWrap, - cx: &mut ViewContext, + + cx: &mut Context, ) { self.soft_wrap_mode_override = Some(mode); cx.notify(); @@ -11518,8 +12116,13 @@ impl Editor { } /// called by the Element so we know what style we were most recently rendered with. - pub(crate) fn set_style(&mut self, style: EditorStyle, cx: &mut ViewContext) { - let rem_size = cx.rem_size(); + pub(crate) fn set_style( + &mut self, + style: EditorStyle, + window: &mut Window, + cx: &mut Context, + ) { + let rem_size = window.rem_size(); self.display_map.update(cx, |map, cx| { map.set_font( style.text.font(), @@ -11536,12 +12139,12 @@ impl Editor { // Called by the element. This method is not designed to be called outside of the editor // element's layout code because it does not notify when rewrapping is computed synchronously. - pub(crate) fn set_wrap_width(&self, width: Option, cx: &mut AppContext) -> bool { + pub(crate) fn set_wrap_width(&self, width: Option, cx: &mut App) -> bool { self.display_map .update(cx, |map, cx| map.set_wrap_width(width, cx)) } - pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext) { + pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context) { if self.soft_wrap_mode_override.is_some() { self.soft_wrap_mode_override.take(); } else { @@ -11557,7 +12160,7 @@ impl Editor { cx.notify(); } - pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, cx: &mut ViewContext) { + pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context) { let Some(workspace) = self.workspace() else { return; }; @@ -11568,7 +12171,12 @@ impl Editor { }); } - pub fn toggle_indent_guides(&mut self, _: &ToggleIndentGuides, cx: &mut ViewContext) { + pub fn toggle_indent_guides( + &mut self, + _: &ToggleIndentGuides, + _: &mut Window, + cx: &mut Context, + ) { let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| { self.buffer .read(cx) @@ -11584,13 +12192,18 @@ impl Editor { self.show_indent_guides } - pub fn toggle_line_numbers(&mut self, _: &ToggleLineNumbers, cx: &mut ViewContext) { + pub fn toggle_line_numbers( + &mut self, + _: &ToggleLineNumbers, + _: &mut Window, + cx: &mut Context, + ) { let mut editor_settings = EditorSettings::get_global(cx).clone(); editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers; EditorSettings::override_global(editor_settings, cx); } - pub fn should_use_relative_line_numbers(&self, cx: &WindowContext) -> bool { + pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool { self.use_relative_line_numbers .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers) } @@ -11598,73 +12211,66 @@ impl Editor { pub fn toggle_relative_line_numbers( &mut self, _: &ToggleRelativeLineNumbers, - cx: &mut ViewContext, + _: &mut Window, + cx: &mut Context, ) { let is_relative = self.should_use_relative_line_numbers(cx); self.set_relative_line_number(Some(!is_relative), cx) } - pub fn set_relative_line_number( - &mut self, - is_relative: Option, - cx: &mut ViewContext, - ) { + pub fn set_relative_line_number(&mut self, is_relative: Option, cx: &mut Context) { self.use_relative_line_numbers = is_relative; cx.notify(); } - pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut ViewContext) { + pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context) { self.show_gutter = show_gutter; cx.notify(); } - pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut ViewContext) { + pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context) { self.show_scrollbars = show_scrollbars; cx.notify(); } - pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut ViewContext) { + pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context) { self.show_line_numbers = Some(show_line_numbers); cx.notify(); } - pub fn set_show_git_diff_gutter( - &mut self, - show_git_diff_gutter: bool, - cx: &mut ViewContext, - ) { + pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context) { self.show_git_diff_gutter = Some(show_git_diff_gutter); cx.notify(); } - pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut ViewContext) { + pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context) { self.show_code_actions = Some(show_code_actions); cx.notify(); } - pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut ViewContext) { + pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context) { self.show_runnables = Some(show_runnables); cx.notify(); } - pub fn set_masked(&mut self, masked: bool, cx: &mut ViewContext) { + pub fn set_masked(&mut self, masked: bool, cx: &mut Context) { if self.display_map.read(cx).masked != masked { self.display_map.update(cx, |map, _| map.masked = masked); } cx.notify() } - pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut ViewContext) { + pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context) { self.show_wrap_guides = Some(show_wrap_guides); cx.notify(); } - pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut ViewContext) { + pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context) { self.show_indent_guides = Some(show_indent_guides); cx.notify(); } - pub fn working_directory(&self, cx: &WindowContext) -> Option { + pub fn working_directory(&self, cx: &App) -> Option { 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(dir) = file.abs_path(cx).parent() { @@ -11680,7 +12286,7 @@ impl Editor { None } - fn target_file<'a>(&self, cx: &'a AppContext) -> Option<&'a dyn language::LocalFile> { + fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> { self.active_excerpt(cx)? .1 .read(cx) @@ -11688,7 +12294,7 @@ impl Editor { .and_then(|f| f.as_local()) } - fn target_file_abs_path(&self, cx: &mut ViewContext) -> Option { + fn target_file_abs_path(&self, cx: &mut Context) -> Option { self.active_excerpt(cx).and_then(|(_, buffer, _)| { let project_path = buffer.read(cx).project_path(cx)?; let project = self.project.as_ref()?.read(cx); @@ -11696,7 +12302,7 @@ impl Editor { }) } - fn target_file_path(&self, cx: &mut ViewContext) -> Option { + fn target_file_path(&self, cx: &mut Context) -> Option { self.active_excerpt(cx).and_then(|(_, buffer, _)| { let project_path = buffer.read(cx).project_path(cx)?; let project = self.project.as_ref()?.read(cx); @@ -11706,13 +12312,18 @@ impl Editor { }) } - pub fn reveal_in_finder(&mut self, _: &RevealInFileManager, cx: &mut ViewContext) { + pub fn reveal_in_finder( + &mut self, + _: &RevealInFileManager, + _window: &mut Window, + cx: &mut Context, + ) { if let Some(target) = self.target_file(cx) { cx.reveal_path(&target.abs_path(cx)); } } - pub fn copy_path(&mut self, _: &CopyPath, cx: &mut ViewContext) { + pub fn copy_path(&mut self, _: &CopyPath, _window: &mut Window, cx: &mut Context) { if let Some(path) = self.target_file_abs_path(cx) { if let Some(path) = path.to_str() { cx.write_to_clipboard(ClipboardItem::new_string(path.to_string())); @@ -11720,7 +12331,12 @@ impl Editor { } } - pub fn copy_relative_path(&mut self, _: &CopyRelativePath, cx: &mut ViewContext) { + pub fn copy_relative_path( + &mut self, + _: &CopyRelativePath, + _window: &mut Window, + cx: &mut Context, + ) { if let Some(path) = self.target_file_path(cx) { if let Some(path) = path.to_str() { cx.write_to_clipboard(ClipboardItem::new_string(path.to_string())); @@ -11728,11 +12344,16 @@ impl Editor { } } - pub fn toggle_git_blame(&mut self, _: &ToggleGitBlame, cx: &mut ViewContext) { + pub fn toggle_git_blame( + &mut self, + _: &ToggleGitBlame, + window: &mut Window, + cx: &mut Context, + ) { self.show_git_blame_gutter = !self.show_git_blame_gutter; if self.show_git_blame_gutter && !self.has_blame_entries(cx) { - self.start_git_blame(true, cx); + self.start_git_blame(true, window, cx); } cx.notify(); @@ -11741,9 +12362,10 @@ impl Editor { pub fn toggle_git_blame_inline( &mut self, _: &ToggleGitBlameInline, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { - self.toggle_git_blame_inline_internal(true, cx); + self.toggle_git_blame_inline_internal(true, window, cx); cx.notify(); } @@ -11751,7 +12373,12 @@ impl Editor { self.git_blame_inline_enabled } - pub fn toggle_selection_menu(&mut self, _: &ToggleSelectionMenu, cx: &mut ViewContext) { + pub fn toggle_selection_menu( + &mut self, + _: &ToggleSelectionMenu, + _: &mut Window, + cx: &mut Context, + ) { self.show_selection_menu = self .show_selection_menu .map(|show_selections_menu| !show_selections_menu) @@ -11760,12 +12387,17 @@ impl Editor { cx.notify(); } - pub fn selection_menu_enabled(&self, cx: &AppContext) -> bool { + pub fn selection_menu_enabled(&self, cx: &App) -> bool { self.show_selection_menu .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu) } - fn start_git_blame(&mut self, user_triggered: bool, cx: &mut ViewContext) { + fn start_git_blame( + &mut self, + user_triggered: bool, + window: &mut Window, + cx: &mut Context, + ) { if let Some(project) = self.project.as_ref() { let Some(buffer) = self.buffer().read(cx).as_singleton() else { return; @@ -11775,12 +12407,12 @@ impl Editor { return; } - let focused = self.focus_handle(cx).contains_focused(cx); + let focused = self.focus_handle(cx).contains_focused(window, cx); let project = project.clone(); - let blame = - cx.new_model(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx)); - self.blame_subscription = Some(cx.observe(&blame, |_, _, cx| cx.notify())); + let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx)); + self.blame_subscription = + Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify())); self.blame = Some(blame); } } @@ -11788,7 +12420,8 @@ impl Editor { fn toggle_git_blame_inline_internal( &mut self, user_triggered: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if self.git_blame_inline_enabled { self.git_blame_inline_enabled = false; @@ -11796,27 +12429,32 @@ impl Editor { self.show_git_blame_inline_delay_task.take(); } else { self.git_blame_inline_enabled = true; - self.start_git_blame_inline(user_triggered, cx); + self.start_git_blame_inline(user_triggered, window, cx); } cx.notify(); } - fn start_git_blame_inline(&mut self, user_triggered: bool, cx: &mut ViewContext) { - self.start_git_blame(user_triggered, cx); + fn start_git_blame_inline( + &mut self, + user_triggered: bool, + window: &mut Window, + cx: &mut Context, + ) { + self.start_git_blame(user_triggered, window, cx); if ProjectSettings::get_global(cx) .git .inline_blame_delay() .is_some() { - self.start_inline_blame_timer(cx); + self.start_inline_blame_timer(window, cx); } else { self.show_git_blame_inline = true } } - pub fn blame(&self) -> Option<&Model> { + pub fn blame(&self) -> Option<&Entity> { self.blame.as_ref() } @@ -11824,23 +12462,23 @@ impl Editor { self.show_git_blame_gutter } - pub fn render_git_blame_gutter(&self, cx: &WindowContext) -> bool { + pub fn render_git_blame_gutter(&self, cx: &App) -> bool { self.show_git_blame_gutter && self.has_blame_entries(cx) } - pub fn render_git_blame_inline(&self, cx: &WindowContext) -> bool { + pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool { self.show_git_blame_inline - && self.focus_handle.is_focused(cx) + && self.focus_handle.is_focused(window) && !self.newest_selection_head_on_empty_line(cx) && self.has_blame_entries(cx) } - fn has_blame_entries(&self, cx: &WindowContext) -> bool { + fn has_blame_entries(&self, cx: &App) -> bool { self.blame() .map_or(false, |blame| blame.read(cx).has_generated_entries()) } - fn newest_selection_head_on_empty_line(&self, cx: &WindowContext) -> bool { + fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool { let cursor_anchor = self.selections.newest_anchor().head(); let snapshot = self.buffer.read(cx).snapshot(cx); @@ -11849,7 +12487,7 @@ impl Editor { snapshot.line_len(buffer_row) == 0 } - fn get_permalink_to_line(&self, cx: &mut ViewContext) -> Task> { + fn get_permalink_to_line(&self, cx: &mut Context) -> Task> { let buffer_and_selection = maybe!({ let selection = self.selections.newest::(cx); let selection_range = selection.range(); @@ -11885,14 +12523,19 @@ impl Editor { }) } - pub fn copy_permalink_to_line(&mut self, _: &CopyPermalinkToLine, cx: &mut ViewContext) { + pub fn copy_permalink_to_line( + &mut self, + _: &CopyPermalinkToLine, + window: &mut Window, + cx: &mut Context, + ) { let permalink_task = self.get_permalink_to_line(cx); let workspace = self.workspace(); - cx.spawn(|_, mut cx| async move { + cx.spawn_in(window, |_, mut cx| async move { match permalink_task.await { Ok(permalink) => { - cx.update(|cx| { + cx.update(|_, cx| { cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string())); }) .ok(); @@ -11904,7 +12547,7 @@ impl Editor { if let Some(workspace) = workspace { workspace - .update(&mut cx, |workspace, cx| { + .update_in(&mut cx, |workspace, _, cx| { struct CopyPermalinkToLine; workspace.show_toast( @@ -11923,7 +12566,12 @@ impl Editor { .detach(); } - pub fn copy_file_location(&mut self, _: &CopyFileLocation, cx: &mut ViewContext) { + pub fn copy_file_location( + &mut self, + _: &CopyFileLocation, + _: &mut Window, + cx: &mut Context, + ) { let selection = self.selections.newest::(cx).start.row + 1; if let Some(file) = self.target_file(cx) { if let Some(path) = file.path().to_str() { @@ -11932,14 +12580,19 @@ impl Editor { } } - pub fn open_permalink_to_line(&mut self, _: &OpenPermalinkToLine, cx: &mut ViewContext) { + pub fn open_permalink_to_line( + &mut self, + _: &OpenPermalinkToLine, + window: &mut Window, + cx: &mut Context, + ) { let permalink_task = self.get_permalink_to_line(cx); let workspace = self.workspace(); - cx.spawn(|_, mut cx| async move { + cx.spawn_in(window, |_, mut cx| async move { match permalink_task.await { Ok(permalink) => { - cx.update(|cx| { + cx.update(|_, cx| { cx.open_url(permalink.as_ref()); }) .ok(); @@ -11970,16 +12623,26 @@ impl Editor { .detach(); } - pub fn insert_uuid_v4(&mut self, _: &InsertUuidV4, cx: &mut ViewContext) { - self.insert_uuid(UuidVersion::V4, cx); + pub fn insert_uuid_v4( + &mut self, + _: &InsertUuidV4, + window: &mut Window, + cx: &mut Context, + ) { + self.insert_uuid(UuidVersion::V4, window, cx); } - pub fn insert_uuid_v7(&mut self, _: &InsertUuidV7, cx: &mut ViewContext) { - self.insert_uuid(UuidVersion::V7, cx); + pub fn insert_uuid_v7( + &mut self, + _: &InsertUuidV7, + window: &mut Window, + cx: &mut Context, + ) { + self.insert_uuid(UuidVersion::V7, window, cx); } - fn insert_uuid(&mut self, version: UuidVersion, cx: &mut ViewContext) { - self.transact(cx, |this, cx| { + fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context) { + self.transact(window, cx, |this, window, cx| { let edits = this .selections .all::(cx) @@ -11993,14 +12656,15 @@ impl Editor { (selection.range(), uuid.to_string()) }); this.edit(edits, cx); - this.refresh_inline_completion(true, false, cx); + this.refresh_inline_completion(true, false, window, cx); }); } pub fn open_selections_in_multibuffer( &mut self, _: &OpenSelectionsInMultibuffer, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let multibuffer = self.buffer.read(cx); @@ -12024,14 +12688,15 @@ impl Editor { let title = multibuffer.title(cx).to_string(); - cx.spawn(|_, mut cx| async move { - workspace.update(&mut cx, |workspace, cx| { + cx.spawn_in(window, |_, mut cx| async move { + workspace.update_in(&mut cx, |workspace, window, cx| { Self::open_locations_in_multibuffer( workspace, locations, format!("Selections for '{title}'"), false, MultibufferSelectionMode::All, + window, cx, ); }) @@ -12048,7 +12713,7 @@ impl Editor { range: Range, color: Hsla, should_autoscroll: bool, - cx: &mut ViewContext, + cx: &mut Context, ) { let snapshot = self.buffer().read(cx).snapshot(cx); let row_highlights = self.highlighted_rows.entry(TypeId::of::()).or_default(); @@ -12125,7 +12790,7 @@ impl Editor { pub fn remove_highlighted_rows( &mut self, ranges_to_remove: Vec>, - cx: &mut ViewContext, + cx: &mut Context, ) { let snapshot = self.buffer().read(cx).snapshot(cx); let row_highlights = self.highlighted_rows.entry(TypeId::of::()).or_default(); @@ -12168,8 +12833,12 @@ impl Editor { /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict. /// Returns a map of display rows that are highlighted and their corresponding highlight color. /// Allows to ignore certain kinds of highlights. - pub fn highlighted_display_rows(&self, cx: &mut WindowContext) -> BTreeMap { - let snapshot = self.snapshot(cx); + pub fn highlighted_display_rows( + &self, + window: &mut Window, + cx: &mut App, + ) -> BTreeMap { + let snapshot = self.snapshot(window, cx); let mut used_highlight_orders = HashMap::default(); self.highlighted_rows .iter() @@ -12217,11 +12886,7 @@ impl Editor { .min() } - pub fn set_search_within_ranges( - &mut self, - ranges: &[Range], - cx: &mut ViewContext, - ) { + pub fn set_search_within_ranges(&mut self, ranges: &[Range], cx: &mut Context) { self.highlight_background::( ranges, |colors| colors.editor_document_highlight_read_background, @@ -12233,7 +12898,7 @@ impl Editor { self.breadcrumb_header = Some(new_header); } - pub fn clear_search_within_ranges(&mut self, cx: &mut ViewContext) { + pub fn clear_search_within_ranges(&mut self, cx: &mut Context) { self.clear_background_highlights::(cx); } @@ -12241,7 +12906,7 @@ impl Editor { &mut self, ranges: &[Range], color_fetcher: fn(&ThemeColors) -> Hsla, - cx: &mut ViewContext, + cx: &mut Context, ) { self.background_highlights .insert(TypeId::of::(), (color_fetcher, Arc::from(ranges))); @@ -12251,7 +12916,7 @@ impl Editor { pub fn clear_background_highlights( &mut self, - cx: &mut ViewContext, + cx: &mut Context, ) -> Option { let text_highlights = self.background_highlights.remove(&TypeId::of::())?; if !text_highlights.1.is_empty() { @@ -12264,8 +12929,8 @@ impl Editor { pub fn highlight_gutter( &mut self, ranges: &[Range], - color_fetcher: fn(&AppContext) -> Hsla, - cx: &mut ViewContext, + color_fetcher: fn(&App) -> Hsla, + cx: &mut Context, ) { self.gutter_highlights .insert(TypeId::of::(), (color_fetcher, Arc::from(ranges))); @@ -12274,7 +12939,7 @@ impl Editor { pub fn clear_gutter_highlights( &mut self, - cx: &mut ViewContext, + cx: &mut Context, ) -> Option { cx.notify(); self.gutter_highlights.remove(&TypeId::of::()) @@ -12283,9 +12948,10 @@ impl Editor { #[cfg(feature = "test-support")] pub fn all_text_background_highlights( &self, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Vec<(Range, Hsla)> { - let snapshot = self.snapshot(cx); + let snapshot = self.snapshot(window, cx); let buffer = &snapshot.buffer_snapshot; let start = buffer.anchor_before(0); let end = buffer.anchor_after(buffer.len()); @@ -12294,10 +12960,7 @@ impl Editor { } #[cfg(feature = "test-support")] - pub fn search_background_highlights( - &mut self, - cx: &mut ViewContext, - ) -> Vec> { + pub fn search_background_highlights(&mut self, cx: &mut Context) -> Vec> { let snapshot = self.buffer().read(cx).snapshot(cx); let highlights = self @@ -12473,7 +13136,7 @@ impl Editor { &self, search_range: Range, display_snapshot: &DisplaySnapshot, - cx: &AppContext, + cx: &App, ) -> Vec<(Range, Hsla)> { let mut results = Vec::new(); for (color_fetcher, ranges) in self.gutter_highlights.values() { @@ -12512,7 +13175,7 @@ impl Editor { &self, search_range: Range, display_snapshot: &DisplaySnapshot, - cx: &WindowContext, + cx: &App, ) -> Vec> { display_snapshot .buffer_snapshot @@ -12542,7 +13205,7 @@ impl Editor { &mut self, ranges: Vec>, style: HighlightStyle, - cx: &mut ViewContext, + cx: &mut Context, ) { self.display_map.update(cx, |map, _| { map.highlight_text(TypeId::of::(), ranges, style) @@ -12554,7 +13217,7 @@ impl Editor { &mut self, highlights: Vec, style: HighlightStyle, - cx: &mut ViewContext, + cx: &mut Context, ) { self.display_map.update(cx, |map, _| { map.highlight_inlays(TypeId::of::(), highlights, style) @@ -12564,12 +13227,12 @@ impl Editor { pub fn text_highlights<'a, T: 'static>( &'a self, - cx: &'a AppContext, + cx: &'a App, ) -> Option<(HighlightStyle, &'a [Range])> { self.display_map.read(cx).text_highlights(TypeId::of::()) } - pub fn clear_highlights(&mut self, cx: &mut ViewContext) { + pub fn clear_highlights(&mut self, cx: &mut Context) { let cleared = self .display_map .update(cx, |map, _| map.clear_highlights(TypeId::of::())); @@ -12578,31 +13241,32 @@ impl Editor { } } - pub fn show_local_cursors(&self, cx: &WindowContext) -> bool { + pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool { (self.read_only(cx) || self.blink_manager.read(cx).visible()) - && self.focus_handle.is_focused(cx) + && self.focus_handle.is_focused(window) } - pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut ViewContext) { + pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context) { self.show_cursor_when_unfocused = is_enabled; cx.notify(); } - pub fn lsp_store(&self, cx: &AppContext) -> Option> { + pub fn lsp_store(&self, cx: &App) -> Option> { self.project .as_ref() .map(|project| project.read(cx).lsp_store()) } - fn on_buffer_changed(&mut self, _: Model, cx: &mut ViewContext) { + fn on_buffer_changed(&mut self, _: Entity, cx: &mut Context) { cx.notify(); } fn on_buffer_event( &mut self, - multibuffer: Model, + multibuffer: &Entity, event: &multi_buffer::Event, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { match event { multi_buffer::Event::Edited { @@ -12612,9 +13276,9 @@ impl Editor { self.scrollbar_marker_state.dirty = true; self.active_indent_guides_state.dirty = true; self.refresh_active_diagnostics(cx); - self.refresh_code_actions(cx); + self.refresh_code_actions(window, cx); if self.has_active_inline_completion() { - self.update_visible_inline_completion(cx); + self.update_visible_inline_completion(window, cx); } if let Some(buffer) = buffer_edited { let buffer_id = buffer.read(cx).remote_id(); @@ -12671,7 +13335,7 @@ impl Editor { let is_via_ssh = project.is_via_ssh(); (telemetry, is_via_ssh) }; - refresh_linked_ranges(self, cx); + refresh_linked_ranges(self, window, cx); telemetry.log_edit_event("editor", is_via_ssh); } multi_buffer::Event::ExcerptsAdded { @@ -12679,7 +13343,7 @@ impl Editor { predecessor, excerpts, } => { - self.tasks_update_task = Some(self.refresh_runnables(cx)); + self.tasks_update_task = Some(self.refresh_runnables(window, cx)); let buffer_id = buffer.read(cx).remote_id(); if self.buffer.read(cx).change_set_for(buffer_id).is_none() { if let Some(project) = &self.project { @@ -12713,12 +13377,12 @@ impl Editor { cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() }) } multi_buffer::Event::Reparsed(buffer_id) => { - self.tasks_update_task = Some(self.refresh_runnables(cx)); + self.tasks_update_task = Some(self.refresh_runnables(window, cx)); cx.emit(EditorEvent::Reparsed(*buffer_id)); } multi_buffer::Event::LanguageChanged(buffer_id) => { - linked_editing_ranges::refresh_linked_ranges(self, cx); + linked_editing_ranges::refresh_linked_ranges(self, window, cx); cx.emit(EditorEvent::Reparsed(*buffer_id)); cx.notify(); } @@ -12742,13 +13406,18 @@ impl Editor { }; } - fn on_display_map_changed(&mut self, _: Model, cx: &mut ViewContext) { + fn on_display_map_changed( + &mut self, + _: Entity, + _: &mut Window, + cx: &mut Context, + ) { cx.notify(); } - fn settings_changed(&mut self, cx: &mut ViewContext) { - self.tasks_update_task = Some(self.refresh_runnables(cx)); - self.refresh_inline_completion(true, false, cx); + fn settings_changed(&mut self, window: &mut Window, cx: &mut Context) { + self.tasks_update_task = Some(self.refresh_runnables(window, cx)); + self.refresh_inline_completion(true, false, window, cx); self.refresh_inlay_hints( InlayHintRefreshReason::SettingsChange(inlay_hint_settings( self.selections.newest_anchor().head(), @@ -12777,7 +13446,7 @@ impl Editor { if self.mode == EditorMode::Full { let inline_blame_enabled = project_settings.git.inline_blame_enabled(); if self.git_blame_inline_enabled != inline_blame_enabled { - self.toggle_git_blame_inline_internal(false, cx); + self.toggle_git_blame_inline_internal(false, window, cx); } } @@ -12795,7 +13464,8 @@ impl Editor { fn open_proposed_changes_editor( &mut self, _: &OpenProposedChangesEditor, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let Some(workspace) = self.workspace() else { cx.propagate(); @@ -12824,37 +13494,51 @@ impl Editor { .into_iter() .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges }) .collect::>(); - let proposed_changes_editor = cx.new_view(|cx| { + let proposed_changes_editor = cx.new(|cx| { ProposedChangesEditor::new( "Proposed changes", proposed_changes_buffers, self.project.clone(), + window, cx, ) }); - cx.window_context().defer(move |cx| { + window.defer(cx, move |window, cx| { workspace.update(cx, |workspace, cx| { workspace.active_pane().update(cx, |pane, cx| { - pane.add_item(Box::new(proposed_changes_editor), true, true, None, cx); + pane.add_item( + Box::new(proposed_changes_editor), + true, + true, + None, + window, + cx, + ); }); }); }); } - pub fn open_excerpts_in_split(&mut self, _: &OpenExcerptsSplit, cx: &mut ViewContext) { - self.open_excerpts_common(None, true, cx) + pub fn open_excerpts_in_split( + &mut self, + _: &OpenExcerptsSplit, + window: &mut Window, + cx: &mut Context, + ) { + self.open_excerpts_common(None, true, window, cx) } - pub fn open_excerpts(&mut self, _: &OpenExcerpts, cx: &mut ViewContext) { - self.open_excerpts_common(None, false, cx) + pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context) { + self.open_excerpts_common(None, false, window, cx) } fn open_excerpts_common( &mut self, jump_data: Option, split: bool, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { let Some(workspace) = self.workspace() else { cx.propagate(); @@ -12948,10 +13632,10 @@ impl Editor { // We defer the pane interaction because we ourselves are a workspace item // and activating a new item causes the pane to call a method on us reentrantly, // which panics if we're on the stack. - cx.window_context().defer(move |cx| { + window.defer(cx, move |window, cx| { workspace.update(cx, |workspace, cx| { let pane = if split { - workspace.adjacent_pane(cx) + workspace.adjacent_pane(window, cx) } else { workspace.active_pane().clone() }; @@ -12977,7 +13661,7 @@ impl Editor { } })?; pane.update(cx, |pane, cx| { - pane.activate_item(pane_item_index, true, true, cx) + pane.activate_item(pane_item_index, true, true, window, cx) }); Some(editor) }) @@ -12988,6 +13672,7 @@ impl Editor { buffer, true, true, + window, cx, ) }); @@ -12998,7 +13683,7 @@ impl Editor { None => Autoscroll::newest(), }; let nav_history = editor.nav_history.take(); - editor.change_selections(Some(autoscroll), cx, |s| { + editor.change_selections(Some(autoscroll), window, cx, |s| { s.select_ranges(ranges); }); editor.nav_history = nav_history; @@ -13008,7 +13693,7 @@ impl Editor { }); } - fn marked_text_ranges(&self, cx: &AppContext) -> Option>> { + fn marked_text_ranges(&self, cx: &App) -> Option>> { let snapshot = self.buffer.read(cx).read(cx); let (_, ranges) = self.text_highlights::(cx)?; Some( @@ -13024,7 +13709,7 @@ impl Editor { fn selection_replacement_ranges( &self, range: Range, - cx: &mut AppContext, + cx: &mut App, ) -> Vec> { let selections = self.selections.all::(cx); let newest_selection = selections @@ -13050,7 +13735,7 @@ impl Editor { &self, event_type: &'static str, file_extension: Option, - cx: &AppContext, + cx: &App, ) { if cfg!(any(test, feature = "test-support")) { return; @@ -13097,7 +13782,12 @@ impl Editor { /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines, /// with each line being an array of {text, highlight} objects. - fn copy_highlight_json(&mut self, _: &CopyHighlightJson, cx: &mut ViewContext) { + fn copy_highlight_json( + &mut self, + _: &CopyHighlightJson, + window: &mut Window, + cx: &mut Context, + ) { #[derive(Serialize)] struct Chunk<'a> { text: String, @@ -13106,7 +13796,7 @@ impl Editor { let snapshot = self.buffer.read(cx).snapshot(cx); let range = self - .selected_text_range(false, cx) + .selected_text_range(false, window, cx) .and_then(|selection| { if selection.range.is_empty() { None @@ -13164,10 +13854,15 @@ impl Editor { cx.write_to_clipboard(ClipboardItem::new_string(lines)); } - pub fn open_context_menu(&mut self, _: &OpenContextMenu, cx: &mut ViewContext) { + pub fn open_context_menu( + &mut self, + _: &OpenContextMenu, + window: &mut Window, + cx: &mut Context, + ) { self.request_autoscroll(Autoscroll::newest(), cx); let position = self.selections.newest_display(cx).start; - mouse_context_menu::deploy_context_menu(self, None, position, cx); + mouse_context_menu::deploy_context_menu(self, None, position, window, cx); } pub fn inlay_hint_cache(&self) -> &InlayHintCache { @@ -13178,7 +13873,8 @@ impl Editor { &mut self, text: &str, relative_utf16_range: Option>, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if !self.input_enabled { cx.emit(EditorEvent::InputIgnored { text: text.into() }); @@ -13186,7 +13882,7 @@ impl Editor { } if let Some(relative_utf16_range) = relative_utf16_range { let selections = self.selections.all::(cx); - self.change_selections(None, cx, |s| { + self.change_selections(None, window, cx, |s| { let new_ranges = selections.into_iter().map(|range| { let start = OffsetUtf16( range @@ -13206,10 +13902,10 @@ impl Editor { }); } - self.handle_input(text, cx); + self.handle_input(text, window, cx); } - pub fn supports_inlay_hints(&self, cx: &AppContext) -> bool { + pub fn supports_inlay_hints(&self, cx: &App) -> bool { let Some(provider) = self.semantics_provider.as_ref() else { return false; }; @@ -13220,16 +13916,11 @@ impl Editor { }); supports } - - pub fn focus(&self, cx: &mut WindowContext) { - cx.focus(&self.focus_handle) + pub fn is_focused(&self, window: &mut Window) -> bool { + self.focus_handle.is_focused(window) } - pub fn is_focused(&self, cx: &WindowContext) -> bool { - self.focus_handle.is_focused(cx) - } - - fn handle_focus(&mut self, cx: &mut ViewContext) { + fn handle_focus(&mut self, window: &mut Window, cx: &mut Context) { cx.emit(EditorEvent::Focused); if let Some(descendant) = self @@ -13237,14 +13928,14 @@ impl Editor { .take() .and_then(|descendant| descendant.upgrade()) { - cx.focus(&descendant); + window.focus(&descendant); } else { if let Some(blame) = self.blame.as_ref() { blame.update(cx, GitBlame::focus) } self.blink_manager.update(cx, BlinkManager::enable); - self.show_cursor_names(cx); + self.show_cursor_names(window, cx); self.buffer.update(cx, |buffer, cx| { buffer.finalize_last_transaction(cx); if self.leader_peer_id.is_none() { @@ -13259,17 +13950,22 @@ impl Editor { } } - fn handle_focus_in(&mut self, cx: &mut ViewContext) { + fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context) { cx.emit(EditorEvent::FocusedIn) } - fn handle_focus_out(&mut self, event: FocusOutEvent, _cx: &mut ViewContext) { + fn handle_focus_out( + &mut self, + event: FocusOutEvent, + _window: &mut Window, + _cx: &mut Context, + ) { if event.blurred != self.focus_handle { self.last_focused_descendant = Some(event.blurred); } } - pub fn handle_blur(&mut self, cx: &mut ViewContext) { + pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context) { self.blink_manager.update(cx, BlinkManager::disable); self.buffer .update(cx, |buffer, cx| buffer.remove_active_selections(cx)); @@ -13277,30 +13973,29 @@ impl Editor { if let Some(blame) = self.blame.as_ref() { blame.update(cx, GitBlame::blur) } - if !self.hover_state.focused(cx) { + if !self.hover_state.focused(window, cx) { hide_hover(self, cx); } - self.hide_context_menu(cx); + self.hide_context_menu(window, cx); cx.emit(EditorEvent::Blurred); cx.notify(); } pub fn register_action( &mut self, - listener: impl Fn(&A, &mut WindowContext) + 'static, + listener: impl Fn(&A, &mut Window, &mut App) + 'static, ) -> Subscription { let id = self.next_editor_action_id.post_inc(); let listener = Arc::new(listener); self.editor_actions.borrow_mut().insert( id, - Box::new(move |cx| { - let cx = cx.window_context(); + Box::new(move |window, _| { let listener = listener.clone(); - cx.on_action(TypeId::of::(), move |action, phase, cx| { + window.on_action(TypeId::of::(), move |action, phase, window, cx| { let action = action.downcast_ref().unwrap(); if phase == DispatchPhase::Bubble { - listener(action, cx) + listener(action, window, cx) } }) }), @@ -13319,7 +14014,8 @@ impl Editor { pub fn revert( &mut self, revert_changes: HashMap, Rope)>>, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { self.buffer().update(cx, |multi_buffer, cx| { for (buffer_id, changes) in revert_changes { @@ -13336,27 +14032,27 @@ impl Editor { } } }); - self.change_selections(None, cx, |selections| selections.refresh()); + self.change_selections(None, window, cx, |selections| selections.refresh()); } pub fn to_pixel_point( &self, source: multi_buffer::Anchor, editor_snapshot: &EditorSnapshot, - cx: &mut ViewContext, + window: &mut Window, ) -> Option> { let source_point = source.to_display_point(editor_snapshot); - self.display_to_pixel_point(source_point, editor_snapshot, cx) + self.display_to_pixel_point(source_point, editor_snapshot, window) } pub fn display_to_pixel_point( &self, source: DisplayPoint, editor_snapshot: &EditorSnapshot, - cx: &WindowContext, + window: &mut Window, ) -> Option> { - let line_height = self.style()?.text.line_height_in_pixels(cx.rem_size()); - let text_layout_details = self.text_layout_details(cx); + let line_height = self.style()?.text.line_height_in_pixels(window.rem_size()); + let text_layout_details = self.text_layout_details(window); let scroll_top = text_layout_details .scroll_anchor .scroll_position(editor_snapshot) @@ -13392,14 +14088,14 @@ impl Editor { .and_then(|item| item.to_any().downcast_ref::()) } - fn character_size(&self, cx: &mut ViewContext) -> gpui::Point { - let text_layout_details = self.text_layout_details(cx); + fn character_size(&self, window: &mut Window) -> gpui::Point { + let text_layout_details = self.text_layout_details(window); let style = &text_layout_details.editor_style; - let font_id = cx.text_system().resolve_font(&style.text.font()); - let font_size = style.text.font_size.to_pixels(cx.rem_size()); - let line_height = style.text.line_height_in_pixels(cx.rem_size()); + let font_id = window.text_system().resolve_font(&style.text.font()); + let font_size = style.text.font_size.to_pixels(window.rem_size()); + let line_height = style.text.line_height_in_pixels(window.rem_size()); - let em_width = cx + let em_width = window .text_system() .typographic_bounds(font_id, font_size, 'm') .unwrap() @@ -13411,10 +14107,10 @@ impl Editor { } fn get_unstaged_changes_for_buffers( - project: &Model, - buffers: impl IntoIterator>, - buffer: Model, - cx: &mut AppContext, + project: &Entity, + buffers: impl IntoIterator>, + buffer: Entity, + cx: &mut App, ) { let mut tasks = Vec::new(); project.update(cx, |project, cx| { @@ -13721,27 +14417,21 @@ fn test_wrap_with_prefix() { } pub trait CollaborationHub { - fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap; - fn user_participant_indices<'a>( - &self, - cx: &'a AppContext, - ) -> &'a HashMap; - fn user_names(&self, cx: &AppContext) -> HashMap; + fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap; + fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap; + fn user_names(&self, cx: &App) -> HashMap; } -impl CollaborationHub for Model { - fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap { +impl CollaborationHub for Entity { + fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap { self.read(cx).collaborators() } - fn user_participant_indices<'a>( - &self, - cx: &'a AppContext, - ) -> &'a HashMap { + fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap { self.read(cx).user_store().read(cx).participant_indices() } - fn user_names(&self, cx: &AppContext) -> HashMap { + fn user_names(&self, cx: &App) -> HashMap { let this = self.read(cx); let user_ids = this.collaborators().values().map(|c| c.user_id); this.user_store().read_with(cx, |user_store, cx| { @@ -13753,94 +14443,95 @@ impl CollaborationHub for Model { pub trait SemanticsProvider { fn hover( &self, - buffer: &Model, + buffer: &Entity, position: text::Anchor, - cx: &mut AppContext, + cx: &mut App, ) -> Option>>; fn inlay_hints( &self, - buffer_handle: Model, + buffer_handle: Entity, range: Range, - cx: &mut AppContext, + cx: &mut App, ) -> Option>>>; fn resolve_inlay_hint( &self, hint: InlayHint, - buffer_handle: Model, + buffer_handle: Entity, server_id: LanguageServerId, - cx: &mut AppContext, + cx: &mut App, ) -> Option>>; - fn supports_inlay_hints(&self, buffer: &Model, cx: &AppContext) -> bool; + fn supports_inlay_hints(&self, buffer: &Entity, cx: &App) -> bool; fn document_highlights( &self, - buffer: &Model, + buffer: &Entity, position: text::Anchor, - cx: &mut AppContext, + cx: &mut App, ) -> Option>>>; fn definitions( &self, - buffer: &Model, + buffer: &Entity, position: text::Anchor, kind: GotoDefinitionKind, - cx: &mut AppContext, + cx: &mut App, ) -> Option>>>; fn range_for_rename( &self, - buffer: &Model, + buffer: &Entity, position: text::Anchor, - cx: &mut AppContext, + cx: &mut App, ) -> Option>>>>; fn perform_rename( &self, - buffer: &Model, + buffer: &Entity, position: text::Anchor, new_name: String, - cx: &mut AppContext, + cx: &mut App, ) -> Option>>; } pub trait CompletionProvider { fn completions( &self, - buffer: &Model, + buffer: &Entity, buffer_position: text::Anchor, trigger: CompletionContext, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Task>>; fn resolve_completions( &self, - buffer: Model, + buffer: Entity, completion_indices: Vec, completions: Rc>>, - cx: &mut ViewContext, + cx: &mut Context, ) -> Task>; fn apply_additional_edits_for_completion( &self, - _buffer: Model, + _buffer: Entity, _completions: Rc>>, _completion_index: usize, _push_to_history: bool, - _cx: &mut ViewContext, + _cx: &mut Context, ) -> Task>> { Task::ready(Ok(None)) } fn is_completion_trigger( &self, - buffer: &Model, + buffer: &Entity, position: language::Anchor, text: &str, trigger_in_words: bool, - cx: &mut ViewContext, + cx: &mut Context, ) -> bool; fn sort_completions(&self) -> bool { @@ -13853,31 +14544,34 @@ pub trait CodeActionProvider { fn code_actions( &self, - buffer: &Model, + buffer: &Entity, range: Range, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Task>>; fn apply_code_action( &self, - buffer_handle: Model, + buffer_handle: Entity, action: CodeAction, excerpt_id: ExcerptId, push_to_history: bool, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Task>; } -impl CodeActionProvider for Model { +impl CodeActionProvider for Entity { fn id(&self) -> Arc { "project".into() } fn code_actions( &self, - buffer: &Model, + buffer: &Entity, range: Range, - cx: &mut WindowContext, + _window: &mut Window, + cx: &mut App, ) -> Task>> { self.update(cx, |project, cx| { project.code_actions(buffer, range, None, cx) @@ -13886,11 +14580,12 @@ impl CodeActionProvider for Model { fn apply_code_action( &self, - buffer_handle: Model, + buffer_handle: Entity, action: CodeAction, _excerpt_id: ExcerptId, push_to_history: bool, - cx: &mut WindowContext, + _window: &mut Window, + cx: &mut App, ) -> Task> { self.update(cx, |project, cx| { project.apply_code_action(buffer_handle, action, push_to_history, cx) @@ -13900,9 +14595,9 @@ impl CodeActionProvider for Model { fn snippet_completions( project: &Project, - buffer: &Model, + buffer: &Entity, buffer_position: text::Anchor, - cx: &mut AppContext, + cx: &mut App, ) -> Task>> { let language = buffer.read(cx).language_at(buffer_position); let language_name = language.as_ref().map(|language| language.lsp_id()); @@ -14035,13 +14730,14 @@ fn snippet_completions( }) } -impl CompletionProvider for Model { +impl CompletionProvider for Entity { fn completions( &self, - buffer: &Model, + buffer: &Entity, buffer_position: text::Anchor, options: CompletionContext, - cx: &mut ViewContext, + _window: &mut Window, + cx: &mut Context, ) -> Task>> { self.update(cx, |project, cx| { let snippets = snippet_completions(project, buffer, buffer_position, cx); @@ -14057,10 +14753,10 @@ impl CompletionProvider for Model { fn resolve_completions( &self, - buffer: Model, + buffer: Entity, completion_indices: Vec, completions: Rc>>, - cx: &mut ViewContext, + cx: &mut Context, ) -> Task> { self.update(cx, |project, cx| { project.lsp_store().update(cx, |lsp_store, cx| { @@ -14071,11 +14767,11 @@ impl CompletionProvider for Model { fn apply_additional_edits_for_completion( &self, - buffer: Model, + buffer: Entity, completions: Rc>>, completion_index: usize, push_to_history: bool, - cx: &mut ViewContext, + cx: &mut Context, ) -> Task>> { self.update(cx, |project, cx| { project.lsp_store().update(cx, |lsp_store, cx| { @@ -14092,11 +14788,11 @@ impl CompletionProvider for Model { fn is_completion_trigger( &self, - buffer: &Model, + buffer: &Entity, position: language::Anchor, text: &str, trigger_in_words: bool, - cx: &mut ViewContext, + cx: &mut Context, ) -> bool { let mut chars = text.chars(); let char = if let Some(char) = chars.next() { @@ -14122,21 +14818,21 @@ impl CompletionProvider for Model { } } -impl SemanticsProvider for Model { +impl SemanticsProvider for Entity { fn hover( &self, - buffer: &Model, + buffer: &Entity, position: text::Anchor, - cx: &mut AppContext, + cx: &mut App, ) -> Option>> { Some(self.update(cx, |project, cx| project.hover(buffer, position, cx))) } fn document_highlights( &self, - buffer: &Model, + buffer: &Entity, position: text::Anchor, - cx: &mut AppContext, + cx: &mut App, ) -> Option>>> { Some(self.update(cx, |project, cx| { project.document_highlights(buffer, position, cx) @@ -14145,10 +14841,10 @@ impl SemanticsProvider for Model { fn definitions( &self, - buffer: &Model, + buffer: &Entity, position: text::Anchor, kind: GotoDefinitionKind, - cx: &mut AppContext, + cx: &mut App, ) -> Option>>> { Some(self.update(cx, |project, cx| match kind { GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx), @@ -14158,7 +14854,7 @@ impl SemanticsProvider for Model { })) } - fn supports_inlay_hints(&self, buffer: &Model, cx: &AppContext) -> bool { + fn supports_inlay_hints(&self, buffer: &Entity, cx: &App) -> bool { // TODO: make this work for remote projects self.read(cx) .language_servers_for_local_buffer(buffer.read(cx), cx) @@ -14173,9 +14869,9 @@ impl SemanticsProvider for Model { fn inlay_hints( &self, - buffer_handle: Model, + buffer_handle: Entity, range: Range, - cx: &mut AppContext, + cx: &mut App, ) -> Option>>> { Some(self.update(cx, |project, cx| { project.inlay_hints(buffer_handle, range, cx) @@ -14185,9 +14881,9 @@ impl SemanticsProvider for Model { fn resolve_inlay_hint( &self, hint: InlayHint, - buffer_handle: Model, + buffer_handle: Entity, server_id: LanguageServerId, - cx: &mut AppContext, + cx: &mut App, ) -> Option>> { Some(self.update(cx, |project, cx| { project.resolve_inlay_hint(hint, buffer_handle, server_id, cx) @@ -14196,9 +14892,9 @@ impl SemanticsProvider for Model { fn range_for_rename( &self, - buffer: &Model, + buffer: &Entity, position: text::Anchor, - cx: &mut AppContext, + cx: &mut App, ) -> Option>>>> { Some(self.update(cx, |project, cx| { let buffer = buffer.clone(); @@ -14228,10 +14924,10 @@ impl SemanticsProvider for Model { fn perform_rename( &self, - buffer: &Model, + buffer: &Entity, position: text::Anchor, new_name: String, - cx: &mut AppContext, + cx: &mut App, ) -> Option>> { Some(self.update(cx, |project, cx| { project.perform_rename(buffer.clone(), position, new_name, cx) @@ -14242,7 +14938,7 @@ impl SemanticsProvider for Model { fn inlay_hint_settings( location: Anchor, snapshot: &MultiBufferSnapshot, - cx: &mut ViewContext, + cx: &mut Context, ) -> InlayHintSettings { let file = snapshot.file_at(location); let language = snapshot.language_at(location).map(|l| l.name()); @@ -14283,7 +14979,7 @@ impl EditorSnapshot { &'a self, range: &'a Range, collaboration_hub: &dyn CollaborationHub, - cx: &'a AppContext, + cx: &'a App, ) -> impl 'a + Iterator { let participant_names = collaboration_hub.user_names(cx); let participant_indices = collaboration_hub.user_participant_indices(cx); @@ -14372,7 +15068,7 @@ impl EditorSnapshot { em_width: Pixels, em_advance: Pixels, max_line_number_width: Pixels, - cx: &AppContext, + cx: &App, ) -> GutterDimensions { if !self.show_gutter { return GutterDimensions::default(); @@ -14451,8 +15147,9 @@ impl EditorSnapshot { &self, buffer_row: MultiBufferRow, row_contains_cursor: bool, - editor: View, - cx: &mut WindowContext, + editor: Entity, + window: &mut Window, + cx: &mut App, ) -> Option { let folded = self.is_line_folded(buffer_row); let mut is_foldable = false; @@ -14465,18 +15162,29 @@ impl EditorSnapshot { match crease { Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => { if let Some(render_toggle) = render_toggle { - let toggle_callback = Arc::new(move |folded, cx: &mut WindowContext| { - if folded { - editor.update(cx, |editor, cx| { - editor.fold_at(&crate::FoldAt { buffer_row }, cx) - }); - } else { - editor.update(cx, |editor, cx| { - editor.unfold_at(&crate::UnfoldAt { buffer_row }, cx) - }); - } - }); - return Some((render_toggle)(buffer_row, folded, toggle_callback, cx)); + let toggle_callback = + Arc::new(move |folded, window: &mut Window, cx: &mut App| { + if folded { + editor.update(cx, |editor, cx| { + editor.fold_at(&crate::FoldAt { buffer_row }, window, cx) + }); + } else { + editor.update(cx, |editor, cx| { + editor.unfold_at( + &crate::UnfoldAt { buffer_row }, + window, + cx, + ) + }); + } + }); + return Some((render_toggle)( + buffer_row, + folded, + toggle_callback, + window, + cx, + )); } } } @@ -14488,11 +15196,11 @@ impl EditorSnapshot { Some( Disclosure::new(("gutter_crease", buffer_row.0), !folded) .toggle_state(folded) - .on_click(cx.listener_for(&editor, move |this, _e, cx| { + .on_click(window.listener_for(&editor, move |this, _e, window, cx| { if folded { - this.unfold_at(&UnfoldAt { buffer_row }, cx); + this.unfold_at(&UnfoldAt { buffer_row }, window, cx); } else { - this.fold_at(&FoldAt { buffer_row }, cx); + this.fold_at(&FoldAt { buffer_row }, window, cx); } })) .into_any_element(), @@ -14505,7 +15213,8 @@ impl EditorSnapshot { pub fn render_crease_trailer( &self, buffer_row: MultiBufferRow, - cx: &mut WindowContext, + window: &mut Window, + cx: &mut App, ) -> Option { let folded = self.is_line_folded(buffer_row); if let Crease::Inline { render_trailer, .. } = self @@ -14513,7 +15222,7 @@ impl EditorSnapshot { .query_row(buffer_row, &self.buffer_snapshot)? { let render_trailer = render_trailer.as_ref()?; - Some(render_trailer(buffer_row, folded, cx)) + Some(render_trailer(buffer_row, folded, window, cx)) } else { None } @@ -14538,7 +15247,7 @@ pub enum EditorEvent { text: Arc, }, ExcerptsAdded { - buffer: Model, + buffer: Entity, predecessor: ExcerptId, excerpts: Vec<(ExcerptId, ExcerptRange)>, }, @@ -14587,14 +15296,14 @@ pub enum EditorEvent { impl EventEmitter for Editor {} -impl FocusableView for Editor { - fn focus_handle(&self, _cx: &AppContext) -> FocusHandle { +impl Focusable for Editor { + fn focus_handle(&self, _cx: &App) -> FocusHandle { self.focus_handle.clone() } } impl Render for Editor { - fn render<'a>(&mut self, cx: &mut ViewContext<'a, Self>) -> impl IntoElement { + fn render<'a>(&mut self, _: &mut Window, cx: &mut Context<'a, Self>) -> impl IntoElement { let settings = ThemeSettings::get_global(cx); let mut text_style = match self.mode { @@ -14630,7 +15339,7 @@ impl Render for Editor { }; EditorElement::new( - cx.view(), + &cx.model(), EditorStyle { background, local_player: cx.theme().players().local(), @@ -14651,7 +15360,8 @@ impl ViewInputHandler for Editor { &mut self, range_utf16: Range, adjusted_range: &mut Option>, - cx: &mut ViewContext, + _: &mut Window, + cx: &mut Context, ) -> Option { let snapshot = self.buffer.read(cx).read(cx); let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left); @@ -14665,7 +15375,8 @@ impl ViewInputHandler for Editor { fn selected_text_range( &mut self, ignore_disabled_input: bool, - cx: &mut ViewContext, + _: &mut Window, + cx: &mut Context, ) -> Option { // Prevent the IME menu from appearing when holding down an alphabetic key // while input is disabled. @@ -14682,13 +15393,13 @@ impl ViewInputHandler for Editor { }) } - fn marked_text_range(&self, cx: &mut ViewContext) -> Option> { + fn marked_text_range(&self, _: &mut Window, cx: &mut Context) -> Option> { let snapshot = self.buffer.read(cx).read(cx); let range = self.text_highlights::(cx)?.1.first()?; Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0) } - fn unmark_text(&mut self, cx: &mut ViewContext) { + fn unmark_text(&mut self, _: &mut Window, cx: &mut Context) { self.clear_highlights::(cx); self.ime_transaction.take(); } @@ -14697,14 +15408,15 @@ impl ViewInputHandler for Editor { &mut self, range_utf16: Option>, text: &str, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if !self.input_enabled { cx.emit(EditorEvent::InputIgnored { text: text.into() }); return; } - self.transact(cx, |this, cx| { + self.transact(window, cx, |this, window, cx| { let new_selected_ranges = if let Some(range_utf16) = range_utf16 { let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end); Some(this.selection_replacement_ranges(range_utf16, cx)) @@ -14736,13 +15448,13 @@ impl ViewInputHandler for Editor { }); if let Some(new_selected_ranges) = new_selected_ranges { - this.change_selections(None, cx, |selections| { + this.change_selections(None, window, cx, |selections| { selections.select_ranges(new_selected_ranges) }); - this.backspace(&Default::default(), cx); + this.backspace(&Default::default(), window, cx); } - this.handle_input(text, cx); + this.handle_input(text, window, cx); }); if let Some(transaction) = self.ime_transaction { @@ -14751,7 +15463,7 @@ impl ViewInputHandler for Editor { }); } - self.unmark_text(cx); + self.unmark_text(window, cx); } fn replace_and_mark_text_in_range( @@ -14759,13 +15471,14 @@ impl ViewInputHandler for Editor { range_utf16: Option>, text: &str, new_selected_range_utf16: Option>, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) { if !self.input_enabled { return; } - let transaction = self.transact(cx, |this, cx| { + let transaction = self.transact(window, cx, |this, window, cx| { let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) { let snapshot = this.buffer.read(cx).read(cx); if let Some(relative_range_utf16) = range_utf16.as_ref() { @@ -14810,7 +15523,7 @@ impl ViewInputHandler for Editor { }); if let Some(ranges) = ranges_to_replace { - this.change_selections(None, cx, |s| s.select_ranges(ranges)); + this.change_selections(None, window, cx, |s| s.select_ranges(ranges)); } let marked_ranges = { @@ -14825,7 +15538,7 @@ impl ViewInputHandler for Editor { }; if text.is_empty() { - this.unmark_text(cx); + this.unmark_text(window, cx); } else { this.highlight_text::( marked_ranges.clone(), @@ -14846,7 +15559,7 @@ impl ViewInputHandler for Editor { let use_auto_surround = this.use_auto_surround; this.set_use_autoclose(false); this.set_use_auto_surround(false); - this.handle_input(text, cx); + this.handle_input(text, window, cx); this.set_use_autoclose(use_autoclose); this.set_use_auto_surround(use_auto_surround); @@ -14864,7 +15577,7 @@ impl ViewInputHandler for Editor { .collect::>(); drop(snapshot); - this.change_selections(None, cx, |selections| { + this.change_selections(None, window, cx, |selections| { selections.select_ranges(new_selected_ranges) }); } @@ -14886,15 +15599,16 @@ impl ViewInputHandler for Editor { &mut self, range_utf16: Range, element_bounds: gpui::Bounds, - cx: &mut ViewContext, + window: &mut Window, + cx: &mut Context, ) -> Option> { - let text_layout_details = self.text_layout_details(cx); + let text_layout_details = self.text_layout_details(window); let gpui::Point { x: em_width, y: line_height, - } = self.character_size(cx); + } = self.character_size(window); - let snapshot = self.snapshot(cx); + let snapshot = self.snapshot(window, cx); let scroll_position = snapshot.scroll_position(); let scroll_left = scroll_position.x * em_width; @@ -15020,7 +15734,7 @@ pub fn diagnostic_block_renderer( Arc::new(move |cx: &mut BlockContext| { let group_id: SharedString = cx.block_id.to_string().into(); - let mut text_style = cx.text_style().clone(); + let mut text_style = cx.window.text_style().clone(); text_style.color = diagnostic_style(diagnostic.severity, cx.theme().status()); let theme_settings = ThemeSettings::get_global(cx); text_style.font_family = theme_settings.buffer_font.family.clone(); @@ -15043,8 +15757,12 @@ pub fn diagnostic_block_renderer( .size(ButtonSize::Compact) .style(ButtonStyle::Transparent) .visible_on_hover(group_id.clone()) - .on_click(move |_click, cx| cx.dispatch_action(Box::new(Cancel))) - .tooltip(|cx| Tooltip::for_action("Close Diagnostics", &Cancel, cx)) + .on_click(move |_click, window, cx| { + window.dispatch_action(Box::new(Cancel), cx) + }) + .tooltip(|window, cx| { + Tooltip::for_action("Close Diagnostics", &Cancel, window, cx) + }) })) }) .child( @@ -15055,17 +15773,19 @@ pub fn diagnostic_block_renderer( .visible_on_hover(group_id.clone()) .on_click({ let message = diagnostic.message.clone(); - move |_click, cx| { + move |_click, _, cx| { cx.write_to_clipboard(ClipboardItem::new_string(message.clone())) } }) - .tooltip(|cx| Tooltip::text("Copy diagnostic message", cx)), + .tooltip(Tooltip::text("Copy diagnostic message")), ) }; - let icon_size = buttons(&diagnostic) - .into_any_element() - .layout_as_root(AvailableSpace::min_size(), cx); + let icon_size = buttons(&diagnostic).into_any_element().layout_as_root( + AvailableSpace::min_size(), + cx.window, + cx.app, + ); h_flex() .id(cx.block_id) @@ -15105,7 +15825,7 @@ fn inline_completion_edit_text( edits: &[(Range, String)], edit_preview: &EditPreview, include_deletions: bool, - cx: &WindowContext, + cx: &App, ) -> Option { let edits = edits .iter() diff --git a/crates/editor/src/editor_settings.rs b/crates/editor/src/editor_settings.rs index 52b69833ec..a69988b8e1 100644 --- a/crates/editor/src/editor_settings.rs +++ b/crates/editor/src/editor_settings.rs @@ -1,4 +1,4 @@ -use gpui::AppContext; +use gpui::App; use language::CursorShape; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -463,7 +463,7 @@ pub struct GutterContent { } impl EditorSettings { - pub fn jupyter_enabled(cx: &AppContext) -> bool { + pub fn jupyter_enabled(cx: &App) -> bool { EditorSettings::get_global(cx).jupyter.enabled } } @@ -473,10 +473,7 @@ impl Settings for EditorSettings { type FileContent = EditorSettingsContent; - fn load( - sources: SettingsSources, - _: &mut AppContext, - ) -> anyhow::Result { + fn load(sources: SettingsSources, _: &mut App) -> anyhow::Result { sources.json_merge() } } diff --git a/crates/editor/src/editor_settings_controls.rs b/crates/editor/src/editor_settings_controls.rs index 50392ab2c9..6275ec97a1 100644 --- a/crates/editor/src/editor_settings_controls.rs +++ b/crates/editor/src/editor_settings_controls.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use gpui::{AppContext, FontFeatures, FontWeight}; +use gpui::{App, FontFeatures, FontWeight}; use project::project_settings::{InlineBlameSettings, ProjectSettings}; use settings::{EditableSettingControl, Settings}; use theme::{FontFamilyCache, ThemeSettings}; @@ -27,7 +27,7 @@ impl EditorSettingsControls { } impl RenderOnce for EditorSettingsControls { - fn render(self, _cx: &mut WindowContext) -> impl IntoElement { + fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement { SettingsContainer::new() .child( SettingsGroup::new("Font") @@ -65,7 +65,7 @@ impl EditableSettingControl for BufferFontFamilyControl { "Buffer Font Family".into() } - fn read(cx: &AppContext) -> Self::Value { + fn read(cx: &App) -> Self::Value { let settings = ThemeSettings::get_global(cx); settings.buffer_font.family.clone() } @@ -73,14 +73,14 @@ impl EditableSettingControl for BufferFontFamilyControl { fn apply( settings: &mut ::FileContent, value: Self::Value, - _cx: &AppContext, + _cx: &App, ) { settings.buffer_font_family = Some(value.to_string()); } } impl RenderOnce for BufferFontFamilyControl { - fn render(self, cx: &mut WindowContext) -> impl IntoElement { + fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement { let value = Self::read(cx); h_flex() @@ -89,18 +89,18 @@ impl RenderOnce for BufferFontFamilyControl { .child(DropdownMenu::new( "buffer-font-family", value.clone(), - ContextMenu::build(cx, |mut menu, cx| { + ContextMenu::build(window, cx, |mut menu, _, cx| { let font_family_cache = FontFamilyCache::global(cx); for font_name in font_family_cache.list_font_families(cx) { menu = menu.custom_entry( { let font_name = font_name.clone(); - move |_cx| Label::new(font_name.clone()).into_any_element() + move |_window, _cx| Label::new(font_name.clone()).into_any_element() }, { let font_name = font_name.clone(); - move |cx| { + move |_window, cx| { Self::write(font_name.clone(), cx); } }, @@ -124,7 +124,7 @@ impl EditableSettingControl for BufferFontSizeControl { "Buffer Font Size".into() } - fn read(cx: &AppContext) -> Self::Value { + fn read(cx: &App) -> Self::Value { let settings = ThemeSettings::get_global(cx); settings.buffer_font_size } @@ -132,14 +132,14 @@ impl EditableSettingControl for BufferFontSizeControl { fn apply( settings: &mut ::FileContent, value: Self::Value, - _cx: &AppContext, + _cx: &App, ) { settings.buffer_font_size = Some(value.into()); } } impl RenderOnce for BufferFontSizeControl { - fn render(self, cx: &mut WindowContext) -> impl IntoElement { + fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { let value = Self::read(cx); h_flex() @@ -148,10 +148,10 @@ impl RenderOnce for BufferFontSizeControl { .child(NumericStepper::new( "buffer-font-size", value.to_string(), - move |_, cx| { + move |_, _, cx| { Self::write(value - px(1.), cx); }, - move |_, cx| { + move |_, _, cx| { Self::write(value + px(1.), cx); }, )) @@ -169,7 +169,7 @@ impl EditableSettingControl for BufferFontWeightControl { "Buffer Font Weight".into() } - fn read(cx: &AppContext) -> Self::Value { + fn read(cx: &App) -> Self::Value { let settings = ThemeSettings::get_global(cx); settings.buffer_font.weight } @@ -177,14 +177,14 @@ impl EditableSettingControl for BufferFontWeightControl { fn apply( settings: &mut ::FileContent, value: Self::Value, - _cx: &AppContext, + _cx: &App, ) { settings.buffer_font_weight = Some(value.0); } } impl RenderOnce for BufferFontWeightControl { - fn render(self, cx: &mut WindowContext) -> impl IntoElement { + fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement { let value = Self::read(cx); h_flex() @@ -193,12 +193,12 @@ impl RenderOnce for BufferFontWeightControl { .child(DropdownMenu::new( "buffer-font-weight", value.0.to_string(), - ContextMenu::build(cx, |mut menu, _cx| { + ContextMenu::build(window, cx, |mut menu, _window, _cx| { for weight in FontWeight::ALL { menu = menu.custom_entry( - move |_cx| Label::new(weight.0.to_string()).into_any_element(), + move |_window, _cx| Label::new(weight.0.to_string()).into_any_element(), { - move |cx| { + move |_, cx| { Self::write(weight, cx); } }, @@ -222,7 +222,7 @@ impl EditableSettingControl for BufferFontLigaturesControl { "Buffer Font Ligatures".into() } - fn read(cx: &AppContext) -> Self::Value { + fn read(cx: &App) -> Self::Value { let settings = ThemeSettings::get_global(cx); settings .buffer_font @@ -234,7 +234,7 @@ impl EditableSettingControl for BufferFontLigaturesControl { fn apply( settings: &mut ::FileContent, value: Self::Value, - _cx: &AppContext, + _cx: &App, ) { let value = if value { 1 } else { 0 }; @@ -255,14 +255,14 @@ impl EditableSettingControl for BufferFontLigaturesControl { } impl RenderOnce for BufferFontLigaturesControl { - fn render(self, cx: &mut WindowContext) -> impl IntoElement { + fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { let value = Self::read(cx); CheckboxWithLabel::new( "buffer-font-ligatures", Label::new(self.name()), value.into(), - |selection, cx| { + |selection, _, cx| { Self::write( match selection { ToggleState::Selected => true, @@ -286,7 +286,7 @@ impl EditableSettingControl for InlineGitBlameControl { "Inline Git Blame".into() } - fn read(cx: &AppContext) -> Self::Value { + fn read(cx: &App) -> Self::Value { let settings = ProjectSettings::get_global(cx); settings.git.inline_blame_enabled() } @@ -294,7 +294,7 @@ impl EditableSettingControl for InlineGitBlameControl { fn apply( settings: &mut ::FileContent, value: Self::Value, - _cx: &AppContext, + _cx: &App, ) { if let Some(inline_blame) = settings.git.inline_blame.as_mut() { inline_blame.enabled = value; @@ -308,14 +308,14 @@ impl EditableSettingControl for InlineGitBlameControl { } impl RenderOnce for InlineGitBlameControl { - fn render(self, cx: &mut WindowContext) -> impl IntoElement { + fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { let value = Self::read(cx); CheckboxWithLabel::new( "inline-git-blame", Label::new(self.name()), value.into(), - |selection, cx| { + |selection, _, cx| { Self::write( match selection { ToggleState::Selected => true, @@ -339,7 +339,7 @@ impl EditableSettingControl for LineNumbersControl { "Line Numbers".into() } - fn read(cx: &AppContext) -> Self::Value { + fn read(cx: &App) -> Self::Value { let settings = EditorSettings::get_global(cx); settings.gutter.line_numbers } @@ -347,7 +347,7 @@ impl EditableSettingControl for LineNumbersControl { fn apply( settings: &mut ::FileContent, value: Self::Value, - _cx: &AppContext, + _cx: &App, ) { if let Some(gutter) = settings.gutter.as_mut() { gutter.line_numbers = Some(value); @@ -361,14 +361,14 @@ impl EditableSettingControl for LineNumbersControl { } impl RenderOnce for LineNumbersControl { - fn render(self, cx: &mut WindowContext) -> impl IntoElement { + fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { let value = Self::read(cx); CheckboxWithLabel::new( "line-numbers", Label::new(self.name()), value.into(), - |selection, cx| { + |selection, _, cx| { Self::write( match selection { ToggleState::Selected => true, @@ -392,7 +392,7 @@ impl EditableSettingControl for RelativeLineNumbersControl { "Relative Line Numbers".into() } - fn read(cx: &AppContext) -> Self::Value { + fn read(cx: &App) -> Self::Value { let settings = EditorSettings::get_global(cx); settings.relative_line_numbers } @@ -400,27 +400,27 @@ impl EditableSettingControl for RelativeLineNumbersControl { fn apply( settings: &mut ::FileContent, value: Self::Value, - _cx: &AppContext, + _cx: &App, ) { settings.relative_line_numbers = Some(value); } } impl RenderOnce for RelativeLineNumbersControl { - fn render(self, cx: &mut WindowContext) -> impl IntoElement { + fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement { let value = Self::read(cx); DropdownMenu::new( "relative-line-numbers", if value { "Relative" } else { "Ascending" }, - ContextMenu::build(cx, |menu, _cx| { + ContextMenu::build(window, cx, |menu, _window, _cx| { menu.custom_entry( - |_cx| Label::new("Ascending").into_any_element(), - move |cx| Self::write(false, cx), + |_window, _cx| Label::new("Ascending").into_any_element(), + move |_, cx| Self::write(false, cx), ) .custom_entry( - |_cx| Label::new("Relative").into_any_element(), - move |cx| Self::write(true, cx), + |_window, _cx| Label::new("Relative").into_any_element(), + move |_, cx| Self::write(true, cx), ) }), ) diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index b0d1043438..c431cd3ae3 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -52,7 +52,7 @@ use workspace::{ fn test_edit_events(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let buffer = cx.new_model(|cx| { + let buffer = cx.new(|cx| { let mut buffer = language::Buffer::local("123456", cx); buffer.set_group_interval(Duration::from_secs(1)); buffer @@ -61,24 +61,31 @@ fn test_edit_events(cx: &mut TestAppContext) { let events = Rc::new(RefCell::new(Vec::new())); let editor1 = cx.add_window({ let events = events.clone(); - |cx| { - let view = cx.view().clone(); - cx.subscribe(&view, move |_, _, event: &EditorEvent, _| match event { - EditorEvent::Edited { .. } => events.borrow_mut().push(("editor1", "edited")), - EditorEvent::BufferEdited => events.borrow_mut().push(("editor1", "buffer edited")), - _ => {} - }) + |window, cx| { + let model = cx.model().clone(); + cx.subscribe_in( + &model, + window, + move |_, _, event: &EditorEvent, _, _| match event { + EditorEvent::Edited { .. } => events.borrow_mut().push(("editor1", "edited")), + EditorEvent::BufferEdited => { + events.borrow_mut().push(("editor1", "buffer edited")) + } + _ => {} + }, + ) .detach(); - Editor::for_buffer(buffer.clone(), None, cx) + Editor::for_buffer(buffer.clone(), None, window, cx) } }); let editor2 = cx.add_window({ let events = events.clone(); - |cx| { - cx.subscribe( - &cx.view().clone(), - move |_, _, event: &EditorEvent, _| match event { + |window, cx| { + cx.subscribe_in( + &cx.model().clone(), + window, + move |_, _, event: &EditorEvent, _, _| match event { EditorEvent::Edited { .. } => events.borrow_mut().push(("editor2", "edited")), EditorEvent::BufferEdited => { events.borrow_mut().push(("editor2", "buffer edited")) @@ -87,14 +94,14 @@ fn test_edit_events(cx: &mut TestAppContext) { }, ) .detach(); - Editor::for_buffer(buffer.clone(), None, cx) + Editor::for_buffer(buffer.clone(), None, window, cx) } }); assert_eq!(mem::take(&mut *events.borrow_mut()), []); // Mutating editor 1 will emit an `Edited` event only for that editor. - _ = editor1.update(cx, |editor, cx| editor.insert("X", cx)); + _ = editor1.update(cx, |editor, window, cx| editor.insert("X", window, cx)); assert_eq!( mem::take(&mut *events.borrow_mut()), [ @@ -105,7 +112,7 @@ fn test_edit_events(cx: &mut TestAppContext) { ); // Mutating editor 2 will emit an `Edited` event only for that editor. - _ = editor2.update(cx, |editor, cx| editor.delete(&Delete, cx)); + _ = editor2.update(cx, |editor, window, cx| editor.delete(&Delete, window, cx)); assert_eq!( mem::take(&mut *events.borrow_mut()), [ @@ -116,7 +123,7 @@ fn test_edit_events(cx: &mut TestAppContext) { ); // Undoing on editor 1 will emit an `Edited` event only for that editor. - _ = editor1.update(cx, |editor, cx| editor.undo(&Undo, cx)); + _ = editor1.update(cx, |editor, window, cx| editor.undo(&Undo, window, cx)); assert_eq!( mem::take(&mut *events.borrow_mut()), [ @@ -127,7 +134,7 @@ fn test_edit_events(cx: &mut TestAppContext) { ); // Redoing on editor 1 will emit an `Edited` event only for that editor. - _ = editor1.update(cx, |editor, cx| editor.redo(&Redo, cx)); + _ = editor1.update(cx, |editor, window, cx| editor.redo(&Redo, window, cx)); assert_eq!( mem::take(&mut *events.borrow_mut()), [ @@ -138,7 +145,7 @@ fn test_edit_events(cx: &mut TestAppContext) { ); // Undoing on editor 2 will emit an `Edited` event only for that editor. - _ = editor2.update(cx, |editor, cx| editor.undo(&Undo, cx)); + _ = editor2.update(cx, |editor, window, cx| editor.undo(&Undo, window, cx)); assert_eq!( mem::take(&mut *events.borrow_mut()), [ @@ -149,7 +156,7 @@ fn test_edit_events(cx: &mut TestAppContext) { ); // Redoing on editor 2 will emit an `Edited` event only for that editor. - _ = editor2.update(cx, |editor, cx| editor.redo(&Redo, cx)); + _ = editor2.update(cx, |editor, window, cx| editor.redo(&Redo, window, cx)); assert_eq!( mem::take(&mut *events.borrow_mut()), [ @@ -160,10 +167,10 @@ fn test_edit_events(cx: &mut TestAppContext) { ); // No event is emitted when the mutation is a no-op. - _ = editor2.update(cx, |editor, cx| { - editor.change_selections(None, cx, |s| s.select_ranges([0..0])); + _ = editor2.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| s.select_ranges([0..0])); - editor.backspace(&Backspace, cx); + editor.backspace(&Backspace, window, cx); }); assert_eq!(mem::take(&mut *events.borrow_mut()), []); } @@ -174,32 +181,32 @@ fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) { let mut now = Instant::now(); let group_interval = Duration::from_millis(1); - let buffer = cx.new_model(|cx| { + let buffer = cx.new(|cx| { let mut buf = language::Buffer::local("123456", cx); buf.set_group_interval(group_interval); buf }); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); - let editor = cx.add_window(|cx| build_editor(buffer.clone(), cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); + let editor = cx.add_window(|window, cx| build_editor(buffer.clone(), window, cx)); - _ = editor.update(cx, |editor, cx| { - editor.start_transaction_at(now, cx); - editor.change_selections(None, cx, |s| s.select_ranges([2..4])); + _ = editor.update(cx, |editor, window, cx| { + editor.start_transaction_at(now, window, cx); + editor.change_selections(None, window, cx, |s| s.select_ranges([2..4])); - editor.insert("cd", cx); + editor.insert("cd", window, cx); editor.end_transaction_at(now, cx); assert_eq!(editor.text(cx), "12cd56"); assert_eq!(editor.selections.ranges(cx), vec![4..4]); - editor.start_transaction_at(now, cx); - editor.change_selections(None, cx, |s| s.select_ranges([4..5])); - editor.insert("e", cx); + editor.start_transaction_at(now, window, cx); + editor.change_selections(None, window, cx, |s| s.select_ranges([4..5])); + editor.insert("e", window, cx); editor.end_transaction_at(now, cx); assert_eq!(editor.text(cx), "12cde6"); assert_eq!(editor.selections.ranges(cx), vec![5..5]); now += group_interval + Duration::from_millis(1); - editor.change_selections(None, cx, |s| s.select_ranges([2..2])); + editor.change_selections(None, window, cx, |s| s.select_ranges([2..2])); // Simulate an edit in another editor buffer.update(cx, |buffer, cx| { @@ -214,31 +221,31 @@ fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) { // Last transaction happened past the group interval in a different editor. // Undo it individually and don't restore selections. - editor.undo(&Undo, cx); + editor.undo(&Undo, window, cx); assert_eq!(editor.text(cx), "12cde6"); assert_eq!(editor.selections.ranges(cx), vec![2..2]); // First two transactions happened within the group interval in this editor. // Undo them together and restore selections. - editor.undo(&Undo, cx); - editor.undo(&Undo, cx); // Undo stack is empty here, so this is a no-op. + editor.undo(&Undo, window, cx); + editor.undo(&Undo, window, cx); // Undo stack is empty here, so this is a no-op. assert_eq!(editor.text(cx), "123456"); assert_eq!(editor.selections.ranges(cx), vec![0..0]); // Redo the first two transactions together. - editor.redo(&Redo, cx); + editor.redo(&Redo, window, cx); assert_eq!(editor.text(cx), "12cde6"); assert_eq!(editor.selections.ranges(cx), vec![5..5]); // Redo the last transaction on its own. - editor.redo(&Redo, cx); + editor.redo(&Redo, window, cx); assert_eq!(editor.text(cx), "ab2cde6"); assert_eq!(editor.selections.ranges(cx), vec![6..6]); // Test empty transactions. - editor.start_transaction_at(now, cx); + editor.start_transaction_at(now, window, cx); editor.end_transaction_at(now, cx); - editor.undo(&Undo, cx); + editor.undo(&Undo, window, cx); assert_eq!(editor.text(cx), "12cde6"); }); } @@ -247,21 +254,21 @@ fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) { fn test_ime_composition(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let buffer = cx.new_model(|cx| { + let buffer = cx.new(|cx| { let mut buffer = language::Buffer::local("abcde", cx); // Ensure automatic grouping doesn't occur. buffer.set_group_interval(Duration::ZERO); buffer }); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); - cx.add_window(|cx| { - let mut editor = build_editor(buffer.clone(), cx); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); + cx.add_window(|window, cx| { + let mut editor = build_editor(buffer.clone(), window, cx); // Start a new IME composition. - editor.replace_and_mark_text_in_range(Some(0..1), "à", None, cx); - editor.replace_and_mark_text_in_range(Some(0..1), "á", None, cx); - editor.replace_and_mark_text_in_range(Some(0..1), "ä", None, cx); + editor.replace_and_mark_text_in_range(Some(0..1), "à", None, window, cx); + editor.replace_and_mark_text_in_range(Some(0..1), "á", None, window, cx); + editor.replace_and_mark_text_in_range(Some(0..1), "ä", None, window, cx); assert_eq!(editor.text(cx), "äbcde"); assert_eq!( editor.marked_text_ranges(cx), @@ -269,32 +276,32 @@ fn test_ime_composition(cx: &mut TestAppContext) { ); // Finalize IME composition. - editor.replace_text_in_range(None, "ā", cx); + editor.replace_text_in_range(None, "ā", window, cx); assert_eq!(editor.text(cx), "ābcde"); assert_eq!(editor.marked_text_ranges(cx), None); // IME composition edits are grouped and are undone/redone at once. - editor.undo(&Default::default(), cx); + editor.undo(&Default::default(), window, cx); assert_eq!(editor.text(cx), "abcde"); assert_eq!(editor.marked_text_ranges(cx), None); - editor.redo(&Default::default(), cx); + editor.redo(&Default::default(), window, cx); assert_eq!(editor.text(cx), "ābcde"); assert_eq!(editor.marked_text_ranges(cx), None); // Start a new IME composition. - editor.replace_and_mark_text_in_range(Some(0..1), "à", None, cx); + editor.replace_and_mark_text_in_range(Some(0..1), "à", None, window, cx); assert_eq!( editor.marked_text_ranges(cx), Some(vec![OffsetUtf16(0)..OffsetUtf16(1)]) ); // Undoing during an IME composition cancels it. - editor.undo(&Default::default(), cx); + editor.undo(&Default::default(), window, cx); assert_eq!(editor.text(cx), "ābcde"); assert_eq!(editor.marked_text_ranges(cx), None); // Start a new IME composition with an invalid marked range, ensuring it gets clipped. - editor.replace_and_mark_text_in_range(Some(4..999), "è", None, cx); + editor.replace_and_mark_text_in_range(Some(4..999), "è", None, window, cx); assert_eq!(editor.text(cx), "ābcdè"); assert_eq!( editor.marked_text_ranges(cx), @@ -302,19 +309,19 @@ fn test_ime_composition(cx: &mut TestAppContext) { ); // Finalize IME composition with an invalid replacement range, ensuring it gets clipped. - editor.replace_text_in_range(Some(4..999), "ę", cx); + editor.replace_text_in_range(Some(4..999), "ę", window, cx); assert_eq!(editor.text(cx), "ābcdę"); assert_eq!(editor.marked_text_ranges(cx), None); // Start a new IME composition with multiple cursors. - editor.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select_ranges([ OffsetUtf16(1)..OffsetUtf16(1), OffsetUtf16(3)..OffsetUtf16(3), OffsetUtf16(5)..OffsetUtf16(5), ]) }); - editor.replace_and_mark_text_in_range(Some(4..5), "XYZ", None, cx); + editor.replace_and_mark_text_in_range(Some(4..5), "XYZ", None, window, cx); assert_eq!(editor.text(cx), "XYZbXYZdXYZ"); assert_eq!( editor.marked_text_ranges(cx), @@ -326,7 +333,7 @@ fn test_ime_composition(cx: &mut TestAppContext) { ); // Ensure the newly-marked range gets treated as relative to the previously-marked ranges. - editor.replace_and_mark_text_in_range(Some(1..2), "1", None, cx); + editor.replace_and_mark_text_in_range(Some(1..2), "1", None, window, cx); assert_eq!(editor.text(cx), "X1ZbX1ZdX1Z"); assert_eq!( editor.marked_text_ranges(cx), @@ -338,7 +345,7 @@ fn test_ime_composition(cx: &mut TestAppContext) { ); // Finalize IME composition with multiple cursors. - editor.replace_text_in_range(Some(9..10), "2", cx); + editor.replace_text_in_range(Some(9..10), "2", window, cx); assert_eq!(editor.text(cx), "X2ZbX2ZdX2Z"); assert_eq!(editor.marked_text_ranges(cx), None); @@ -350,83 +357,87 @@ fn test_ime_composition(cx: &mut TestAppContext) { fn test_selection_with_mouse(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let editor = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\nddddddd\n", cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = editor.update(cx, |view, cx| { - view.begin_selection(DisplayPoint::new(DisplayRow(2), 2), false, 1, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.begin_selection(DisplayPoint::new(DisplayRow(2), 2), false, 1, window, cx); }); assert_eq!( editor - .update(cx, |view, cx| view.selections.display_ranges(cx)) + .update(cx, |editor, _, cx| editor.selections.display_ranges(cx)) .unwrap(), [DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(2), 2)] ); - _ = editor.update(cx, |view, cx| { - view.update_selection( + _ = editor.update(cx, |editor, window, cx| { + editor.update_selection( DisplayPoint::new(DisplayRow(3), 3), 0, gpui::Point::::default(), + window, cx, ); }); assert_eq!( editor - .update(cx, |view, cx| view.selections.display_ranges(cx)) + .update(cx, |editor, _, cx| editor.selections.display_ranges(cx)) .unwrap(), [DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(3), 3)] ); - _ = editor.update(cx, |view, cx| { - view.update_selection( + _ = editor.update(cx, |editor, window, cx| { + editor.update_selection( DisplayPoint::new(DisplayRow(1), 1), 0, gpui::Point::::default(), + window, cx, ); }); assert_eq!( editor - .update(cx, |view, cx| view.selections.display_ranges(cx)) + .update(cx, |editor, _, cx| editor.selections.display_ranges(cx)) .unwrap(), [DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(1), 1)] ); - _ = editor.update(cx, |view, cx| { - view.end_selection(cx); - view.update_selection( + _ = editor.update(cx, |editor, window, cx| { + editor.end_selection(window, cx); + editor.update_selection( DisplayPoint::new(DisplayRow(3), 3), 0, gpui::Point::::default(), + window, cx, ); }); assert_eq!( editor - .update(cx, |view, cx| view.selections.display_ranges(cx)) + .update(cx, |editor, _, cx| editor.selections.display_ranges(cx)) .unwrap(), [DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(1), 1)] ); - _ = editor.update(cx, |view, cx| { - view.begin_selection(DisplayPoint::new(DisplayRow(3), 3), true, 1, cx); - view.update_selection( + _ = editor.update(cx, |editor, window, cx| { + editor.begin_selection(DisplayPoint::new(DisplayRow(3), 3), true, 1, window, cx); + editor.update_selection( DisplayPoint::new(DisplayRow(0), 0), 0, gpui::Point::::default(), + window, cx, ); }); assert_eq!( editor - .update(cx, |view, cx| view.selections.display_ranges(cx)) + .update(cx, |editor, _, cx| editor.selections.display_ranges(cx)) .unwrap(), [ DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(1), 1), @@ -434,13 +445,13 @@ fn test_selection_with_mouse(cx: &mut TestAppContext) { ] ); - _ = editor.update(cx, |view, cx| { - view.end_selection(cx); + _ = editor.update(cx, |editor, window, cx| { + editor.end_selection(window, cx); }); assert_eq!( editor - .update(cx, |view, cx| view.selections.display_ranges(cx)) + .update(cx, |editor, _, cx| editor.selections.display_ranges(cx)) .unwrap(), [DisplayPoint::new(DisplayRow(3), 3)..DisplayPoint::new(DisplayRow(0), 0)] ); @@ -450,30 +461,30 @@ fn test_selection_with_mouse(cx: &mut TestAppContext) { fn test_multiple_cursor_removal(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let editor = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\nddddddd\n", cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = editor.update(cx, |view, cx| { - view.begin_selection(DisplayPoint::new(DisplayRow(2), 1), false, 1, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.begin_selection(DisplayPoint::new(DisplayRow(2), 1), false, 1, window, cx); }); - _ = editor.update(cx, |view, cx| { - view.end_selection(cx); + _ = editor.update(cx, |editor, window, cx| { + editor.end_selection(window, cx); }); - _ = editor.update(cx, |view, cx| { - view.begin_selection(DisplayPoint::new(DisplayRow(3), 2), true, 1, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.begin_selection(DisplayPoint::new(DisplayRow(3), 2), true, 1, window, cx); }); - _ = editor.update(cx, |view, cx| { - view.end_selection(cx); + _ = editor.update(cx, |editor, window, cx| { + editor.end_selection(window, cx); }); assert_eq!( editor - .update(cx, |view, cx| view.selections.display_ranges(cx)) + .update(cx, |editor, _, cx| editor.selections.display_ranges(cx)) .unwrap(), [ DisplayPoint::new(DisplayRow(2), 1)..DisplayPoint::new(DisplayRow(2), 1), @@ -481,17 +492,17 @@ fn test_multiple_cursor_removal(cx: &mut TestAppContext) { ] ); - _ = editor.update(cx, |view, cx| { - view.begin_selection(DisplayPoint::new(DisplayRow(2), 1), true, 1, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.begin_selection(DisplayPoint::new(DisplayRow(2), 1), true, 1, window, cx); }); - _ = editor.update(cx, |view, cx| { - view.end_selection(cx); + _ = editor.update(cx, |editor, window, cx| { + editor.end_selection(window, cx); }); assert_eq!( editor - .update(cx, |view, cx| view.selections.display_ranges(cx)) + .update(cx, |editor, _, cx| editor.selections.display_ranges(cx)) .unwrap(), [DisplayPoint::new(DisplayRow(3), 2)..DisplayPoint::new(DisplayRow(3), 2)] ); @@ -501,42 +512,44 @@ fn test_multiple_cursor_removal(cx: &mut TestAppContext) { fn test_canceling_pending_selection(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.begin_selection(DisplayPoint::new(DisplayRow(2), 2), false, 1, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.begin_selection(DisplayPoint::new(DisplayRow(2), 2), false, 1, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), [DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(2), 2)] ); }); - _ = view.update(cx, |view, cx| { - view.update_selection( + _ = editor.update(cx, |editor, window, cx| { + editor.update_selection( DisplayPoint::new(DisplayRow(3), 3), 0, gpui::Point::::default(), + window, cx, ); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), [DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(3), 3)] ); }); - _ = view.update(cx, |view, cx| { - view.cancel(&Cancel, cx); - view.update_selection( + _ = editor.update(cx, |editor, window, cx| { + editor.cancel(&Cancel, window, cx); + editor.update_selection( DisplayPoint::new(DisplayRow(1), 1), 0, gpui::Point::::default(), + window, cx, ); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), [DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(3), 3)] ); }); @@ -546,33 +559,33 @@ fn test_canceling_pending_selection(cx: &mut TestAppContext) { fn test_movement_actions_with_pending_selection(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.begin_selection(DisplayPoint::new(DisplayRow(2), 2), false, 1, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.begin_selection(DisplayPoint::new(DisplayRow(2), 2), false, 1, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), [DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(2), 2)] ); - view.move_down(&Default::default(), cx); + editor.move_down(&Default::default(), window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), [DisplayPoint::new(DisplayRow(3), 2)..DisplayPoint::new(DisplayRow(3), 2)] ); - view.begin_selection(DisplayPoint::new(DisplayRow(2), 2), false, 1, cx); + editor.begin_selection(DisplayPoint::new(DisplayRow(2), 2), false, 1, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), [DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(2), 2)] ); - view.move_up(&Default::default(), cx); + editor.move_up(&Default::default(), window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), [DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(1), 2)] ); }); @@ -593,38 +606,47 @@ fn test_clone(cx: &mut TestAppContext) { true, ); - let editor = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple(&text, cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = editor.update(cx, |editor, cx| { - editor.change_selections(None, cx, |s| s.select_ranges(selection_ranges.clone())); + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { + s.select_ranges(selection_ranges.clone()) + }); editor.fold_creases( vec![ Crease::simple(Point::new(1, 0)..Point::new(2, 0), FoldPlaceholder::test()), Crease::simple(Point::new(3, 0)..Point::new(4, 0), FoldPlaceholder::test()), ], true, + window, cx, ); }); let cloned_editor = editor - .update(cx, |editor, cx| { - cx.open_window(Default::default(), |cx| cx.new_view(|cx| editor.clone(cx))) + .update(cx, |editor, _, cx| { + cx.open_window(Default::default(), |window, cx| { + cx.new(|cx| editor.clone(window, cx)) + }) }) .unwrap() .unwrap(); - let snapshot = editor.update(cx, |e, cx| e.snapshot(cx)).unwrap(); - let cloned_snapshot = cloned_editor.update(cx, |e, cx| e.snapshot(cx)).unwrap(); + let snapshot = editor + .update(cx, |e, window, cx| e.snapshot(window, cx)) + .unwrap(); + let cloned_snapshot = cloned_editor + .update(cx, |e, window, cx| e.snapshot(window, cx)) + .unwrap(); assert_eq!( cloned_editor - .update(cx, |e, cx| e.display_text(cx)) + .update(cx, |e, _, cx| e.display_text(cx)) .unwrap(), - editor.update(cx, |e, cx| e.display_text(cx)).unwrap() + editor.update(cx, |e, _, cx| e.display_text(cx)).unwrap() ); assert_eq!( cloned_snapshot @@ -634,18 +656,18 @@ fn test_clone(cx: &mut TestAppContext) { ); assert_set_eq!( cloned_editor - .update(cx, |editor, cx| editor.selections.ranges::(cx)) + .update(cx, |editor, _, cx| editor.selections.ranges::(cx)) .unwrap(), editor - .update(cx, |editor, cx| editor.selections.ranges(cx)) + .update(cx, |editor, _, cx| editor.selections.ranges(cx)) .unwrap() ); assert_set_eq!( cloned_editor - .update(cx, |e, cx| e.selections.display_ranges(cx)) + .update(cx, |e, _window, cx| e.selections.display_ranges(cx)) .unwrap(), editor - .update(cx, |e, cx| e.selections.display_ranges(cx)) + .update(cx, |e, _, cx| e.selections.display_ranges(cx)) .unwrap() ); } @@ -658,30 +680,30 @@ async fn test_navigation_history(cx: &mut TestAppContext) { let fs = FakeFs::new(cx.executor()); let project = Project::test(fs, [], cx).await; - let workspace = cx.add_window(|cx| Workspace::test_new(project, cx)); + let workspace = cx.add_window(|window, cx| Workspace::test_new(project, window, cx)); let pane = workspace - .update(cx, |workspace, _| workspace.active_pane().clone()) + .update(cx, |workspace, _, _| workspace.active_pane().clone()) .unwrap(); - _ = workspace.update(cx, |_v, cx| { - cx.new_view(|cx| { + _ = workspace.update(cx, |_v, window, cx| { + cx.new(|cx| { let buffer = MultiBuffer::build_simple(&sample_text(300, 5, 'a'), cx); - let mut editor = build_editor(buffer.clone(), cx); - let handle = cx.view(); - editor.set_nav_history(Some(pane.read(cx).nav_history_for_item(handle))); + let mut editor = build_editor(buffer.clone(), window, cx); + let handle = cx.model(); + editor.set_nav_history(Some(pane.read(cx).nav_history_for_item(&handle))); - fn pop_history(editor: &mut Editor, cx: &mut WindowContext) -> Option { + fn pop_history(editor: &mut Editor, cx: &mut App) -> Option { editor.nav_history.as_mut().unwrap().pop_backward(cx) } // Move the cursor a small distance. // Nothing is added to the navigation history. - editor.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0) ]) }); - editor.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(3), 0)..DisplayPoint::new(DisplayRow(3), 0) ]) @@ -690,13 +712,13 @@ async fn test_navigation_history(cx: &mut TestAppContext) { // Move the cursor a large distance. // The history can jump back to the previous position. - editor.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(13), 0)..DisplayPoint::new(DisplayRow(13), 3) ]) }); let nav_entry = pop_history(&mut editor, cx).unwrap(); - editor.navigate(nav_entry.data.unwrap(), cx); + editor.navigate(nav_entry.data.unwrap(), window, cx); assert_eq!(nav_entry.item.id(), cx.entity_id()); assert_eq!( editor.selections.display_ranges(cx), @@ -706,8 +728,8 @@ async fn test_navigation_history(cx: &mut TestAppContext) { // Move the cursor a small distance via the mouse. // Nothing is added to the navigation history. - editor.begin_selection(DisplayPoint::new(DisplayRow(5), 0), false, 1, cx); - editor.end_selection(cx); + editor.begin_selection(DisplayPoint::new(DisplayRow(5), 0), false, 1, window, cx); + editor.end_selection(window, cx); assert_eq!( editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(5), 0)..DisplayPoint::new(DisplayRow(5), 0)] @@ -716,14 +738,14 @@ async fn test_navigation_history(cx: &mut TestAppContext) { // Move the cursor a large distance via the mouse. // The history can jump back to the previous position. - editor.begin_selection(DisplayPoint::new(DisplayRow(15), 0), false, 1, cx); - editor.end_selection(cx); + editor.begin_selection(DisplayPoint::new(DisplayRow(15), 0), false, 1, window, cx); + editor.end_selection(window, cx); assert_eq!( editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(15), 0)..DisplayPoint::new(DisplayRow(15), 0)] ); let nav_entry = pop_history(&mut editor, cx).unwrap(); - editor.navigate(nav_entry.data.unwrap(), cx); + editor.navigate(nav_entry.data.unwrap(), window, cx); assert_eq!(nav_entry.item.id(), cx.entity_id()); assert_eq!( editor.selections.display_ranges(cx), @@ -732,16 +754,16 @@ async fn test_navigation_history(cx: &mut TestAppContext) { assert!(pop_history(&mut editor, cx).is_none()); // Set scroll position to check later - editor.set_scroll_position(gpui::Point::::new(5.5, 5.5), cx); + editor.set_scroll_position(gpui::Point::::new(5.5, 5.5), window, cx); let original_scroll_position = editor.scroll_manager.anchor(); // Jump to the end of the document and adjust scroll - editor.move_to_end(&MoveToEnd, cx); - editor.set_scroll_position(gpui::Point::::new(-2.5, -0.5), cx); + editor.move_to_end(&MoveToEnd, window, cx); + editor.set_scroll_position(gpui::Point::::new(-2.5, -0.5), window, cx); assert_ne!(editor.scroll_manager.anchor(), original_scroll_position); let nav_entry = pop_history(&mut editor, cx).unwrap(); - editor.navigate(nav_entry.data.unwrap(), cx); + editor.navigate(nav_entry.data.unwrap(), window, cx); assert_eq!(editor.scroll_manager.anchor(), original_scroll_position); // Ensure we don't panic when navigation data contains invalid anchors *and* points. @@ -758,6 +780,7 @@ async fn test_navigation_history(cx: &mut TestAppContext) { }, scroll_top_row: invalid_point.row, }), + window, cx, ); assert_eq!( @@ -778,31 +801,33 @@ async fn test_navigation_history(cx: &mut TestAppContext) { fn test_cancel(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.begin_selection(DisplayPoint::new(DisplayRow(3), 4), false, 1, cx); - view.update_selection( + _ = editor.update(cx, |editor, window, cx| { + editor.begin_selection(DisplayPoint::new(DisplayRow(3), 4), false, 1, window, cx); + editor.update_selection( DisplayPoint::new(DisplayRow(1), 1), 0, gpui::Point::::default(), + window, cx, ); - view.end_selection(cx); + editor.end_selection(window, cx); - view.begin_selection(DisplayPoint::new(DisplayRow(0), 1), true, 1, cx); - view.update_selection( + editor.begin_selection(DisplayPoint::new(DisplayRow(0), 1), true, 1, window, cx); + editor.update_selection( DisplayPoint::new(DisplayRow(0), 3), 0, gpui::Point::::default(), + window, cx, ); - view.end_selection(cx); + editor.end_selection(window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), [ DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 3), DisplayPoint::new(DisplayRow(3), 4)..DisplayPoint::new(DisplayRow(1), 1), @@ -810,18 +835,18 @@ fn test_cancel(cx: &mut TestAppContext) { ); }); - _ = view.update(cx, |view, cx| { - view.cancel(&Cancel, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.cancel(&Cancel, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), [DisplayPoint::new(DisplayRow(3), 4)..DisplayPoint::new(DisplayRow(1), 1)] ); }); - _ = view.update(cx, |view, cx| { - view.cancel(&Cancel, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.cancel(&Cancel, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), [DisplayPoint::new(DisplayRow(1), 1)..DisplayPoint::new(DisplayRow(1), 1)] ); }); @@ -831,7 +856,7 @@ fn test_cancel(cx: &mut TestAppContext) { fn test_fold_action(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple( &" impl Foo { @@ -853,18 +878,18 @@ fn test_fold_action(cx: &mut TestAppContext) { .unindent(), cx, ); - build_editor(buffer.clone(), cx) + build_editor(buffer.clone(), window, cx) }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(7), 0)..DisplayPoint::new(DisplayRow(12), 0) ]); }); - view.fold(&Fold, cx); + editor.fold(&Fold, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), " impl Foo { // Hello! @@ -883,9 +908,9 @@ fn test_fold_action(cx: &mut TestAppContext) { .unindent(), ); - view.fold(&Fold, cx); + editor.fold(&Fold, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), " impl Foo {⋯ } @@ -893,9 +918,9 @@ fn test_fold_action(cx: &mut TestAppContext) { .unindent(), ); - view.unfold_lines(&UnfoldLines, cx); + editor.unfold_lines(&UnfoldLines, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), " impl Foo { // Hello! @@ -914,8 +939,11 @@ fn test_fold_action(cx: &mut TestAppContext) { .unindent(), ); - view.unfold_lines(&UnfoldLines, cx); - assert_eq!(view.display_text(cx), view.buffer.read(cx).read(cx).text()); + editor.unfold_lines(&UnfoldLines, window, cx); + assert_eq!( + editor.display_text(cx), + editor.buffer.read(cx).read(cx).text() + ); }); } @@ -923,7 +951,7 @@ fn test_fold_action(cx: &mut TestAppContext) { fn test_fold_action_whitespace_sensitive_language(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple( &" class Foo: @@ -941,18 +969,18 @@ fn test_fold_action_whitespace_sensitive_language(cx: &mut TestAppContext) { .unindent(), cx, ); - build_editor(buffer.clone(), cx) + build_editor(buffer.clone(), window, cx) }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(6), 0)..DisplayPoint::new(DisplayRow(10), 0) ]); }); - view.fold(&Fold, cx); + editor.fold(&Fold, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), " class Foo: # Hello! @@ -967,18 +995,18 @@ fn test_fold_action_whitespace_sensitive_language(cx: &mut TestAppContext) { .unindent(), ); - view.fold(&Fold, cx); + editor.fold(&Fold, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), " class Foo:⋯ " .unindent(), ); - view.unfold_lines(&UnfoldLines, cx); + editor.unfold_lines(&UnfoldLines, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), " class Foo: # Hello! @@ -993,8 +1021,11 @@ fn test_fold_action_whitespace_sensitive_language(cx: &mut TestAppContext) { .unindent(), ); - view.unfold_lines(&UnfoldLines, cx); - assert_eq!(view.display_text(cx), view.buffer.read(cx).read(cx).text()); + editor.unfold_lines(&UnfoldLines, window, cx); + assert_eq!( + editor.display_text(cx), + editor.buffer.read(cx).read(cx).text() + ); }); } @@ -1002,7 +1033,7 @@ fn test_fold_action_whitespace_sensitive_language(cx: &mut TestAppContext) { fn test_fold_action_multiple_line_breaks(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple( &" class Foo: @@ -1023,18 +1054,18 @@ fn test_fold_action_multiple_line_breaks(cx: &mut TestAppContext) { .unindent(), cx, ); - build_editor(buffer.clone(), cx) + build_editor(buffer.clone(), window, cx) }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(6), 0)..DisplayPoint::new(DisplayRow(11), 0) ]); }); - view.fold(&Fold, cx); + editor.fold(&Fold, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), " class Foo: # Hello! @@ -1052,9 +1083,9 @@ fn test_fold_action_multiple_line_breaks(cx: &mut TestAppContext) { .unindent(), ); - view.fold(&Fold, cx); + editor.fold(&Fold, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), " class Foo:⋯ @@ -1063,9 +1094,9 @@ fn test_fold_action_multiple_line_breaks(cx: &mut TestAppContext) { .unindent(), ); - view.unfold_lines(&UnfoldLines, cx); + editor.unfold_lines(&UnfoldLines, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), " class Foo: # Hello! @@ -1083,8 +1114,11 @@ fn test_fold_action_multiple_line_breaks(cx: &mut TestAppContext) { .unindent(), ); - view.unfold_lines(&UnfoldLines, cx); - assert_eq!(view.display_text(cx), view.buffer.read(cx).read(cx).text()); + editor.unfold_lines(&UnfoldLines, window, cx); + assert_eq!( + editor.display_text(cx), + editor.buffer.read(cx).read(cx).text() + ); }); } @@ -1092,7 +1126,7 @@ fn test_fold_action_multiple_line_breaks(cx: &mut TestAppContext) { fn test_fold_at_level(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple( &" class Foo: @@ -1119,13 +1153,13 @@ fn test_fold_at_level(cx: &mut TestAppContext) { .unindent(), cx, ); - build_editor(buffer.clone(), cx) + build_editor(buffer.clone(), window, cx) }); - _ = view.update(cx, |view, cx| { - view.fold_at_level(&FoldAtLevel { level: 2 }, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.fold_at_level(&FoldAtLevel { level: 2 }, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), " class Foo: # Hello! @@ -1147,9 +1181,9 @@ fn test_fold_at_level(cx: &mut TestAppContext) { .unindent(), ); - view.fold_at_level(&FoldAtLevel { level: 1 }, cx); + editor.fold_at_level(&FoldAtLevel { level: 1 }, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), " class Foo:⋯ @@ -1161,10 +1195,10 @@ fn test_fold_at_level(cx: &mut TestAppContext) { .unindent(), ); - view.unfold_all(&UnfoldAll, cx); - view.fold_at_level(&FoldAtLevel { level: 0 }, cx); + editor.unfold_all(&UnfoldAll, window, cx); + editor.fold_at_level(&FoldAtLevel { level: 0 }, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), " class Foo: # Hello! @@ -1190,7 +1224,10 @@ fn test_fold_at_level(cx: &mut TestAppContext) { .unindent(), ); - assert_eq!(view.display_text(cx), view.buffer.read(cx).read(cx).text()); + assert_eq!( + editor.display_text(cx), + editor.buffer.read(cx).read(cx).text() + ); }); } @@ -1199,7 +1236,7 @@ fn test_move_cursor(cx: &mut TestAppContext) { init_test(cx, |_| {}); let buffer = cx.update(|cx| MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx)); - let view = cx.add_window(|cx| build_editor(buffer.clone(), cx)); + let editor = cx.add_window(|window, cx| build_editor(buffer.clone(), window, cx)); buffer.update(cx, |buffer, cx| { buffer.edit( @@ -1211,62 +1248,62 @@ fn test_move_cursor(cx: &mut TestAppContext) { cx, ); }); - _ = view.update(cx, |view, cx| { + _ = editor.update(cx, |editor, window, cx| { assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0)] ); - view.move_down(&MoveDown, cx); + editor.move_down(&MoveDown, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0)] ); - view.move_right(&MoveRight, cx); + editor.move_right(&MoveRight, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(1), 4)..DisplayPoint::new(DisplayRow(1), 4)] ); - view.move_left(&MoveLeft, cx); + editor.move_left(&MoveLeft, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0)] ); - view.move_up(&MoveUp, cx); + editor.move_up(&MoveUp, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0)] ); - view.move_to_end(&MoveToEnd, cx); + editor.move_to_end(&MoveToEnd, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(5), 6)..DisplayPoint::new(DisplayRow(5), 6)] ); - view.move_to_beginning(&MoveToBeginning, cx); + editor.move_to_beginning(&MoveToBeginning, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0)] ); - view.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 2) ]); }); - view.select_to_beginning(&SelectToBeginning, cx); + editor.select_to_beginning(&SelectToBeginning, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 0)] ); - view.select_to_end(&SelectToEnd, cx); + editor.select_to_end(&SelectToEnd, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(5), 6)] ); }); @@ -1278,113 +1315,114 @@ fn test_move_cursor(cx: &mut TestAppContext) { fn test_move_cursor_multibyte(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { - let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcde\nαβγδε", cx); - build_editor(buffer.clone(), cx) + let editor = cx.add_window(|window, cx| { + let buffer = MultiBuffer::build_simple("🟥🟧🟨🟩🟦🟪\nabcde\nαβγδε", cx); + build_editor(buffer.clone(), window, cx) }); - assert_eq!('ⓐ'.len_utf8(), 3); + assert_eq!('🟥'.len_utf8(), 4); assert_eq!('α'.len_utf8(), 2); - _ = view.update(cx, |view, cx| { - view.fold_creases( + _ = editor.update(cx, |editor, window, cx| { + editor.fold_creases( vec![ - Crease::simple(Point::new(0, 6)..Point::new(0, 12), FoldPlaceholder::test()), + Crease::simple(Point::new(0, 8)..Point::new(0, 16), FoldPlaceholder::test()), Crease::simple(Point::new(1, 2)..Point::new(1, 4), FoldPlaceholder::test()), Crease::simple(Point::new(2, 4)..Point::new(2, 8), FoldPlaceholder::test()), ], true, + window, cx, ); - assert_eq!(view.display_text(cx), "ⓐⓑ⋯ⓔ\nab⋯e\nαβ⋯ε"); + assert_eq!(editor.display_text(cx), "🟥🟧⋯🟦🟪\nab⋯e\nαβ⋯ε"); - view.move_right(&MoveRight, cx); + editor.move_right(&MoveRight, window, cx); assert_eq!( - view.selections.display_ranges(cx), - &[empty_range(0, "ⓐ".len())] + editor.selections.display_ranges(cx), + &[empty_range(0, "🟥".len())] ); - view.move_right(&MoveRight, cx); + editor.move_right(&MoveRight, window, cx); assert_eq!( - view.selections.display_ranges(cx), - &[empty_range(0, "ⓐⓑ".len())] + editor.selections.display_ranges(cx), + &[empty_range(0, "🟥🟧".len())] ); - view.move_right(&MoveRight, cx); + editor.move_right(&MoveRight, window, cx); assert_eq!( - view.selections.display_ranges(cx), - &[empty_range(0, "ⓐⓑ⋯".len())] + editor.selections.display_ranges(cx), + &[empty_range(0, "🟥🟧⋯".len())] ); - view.move_down(&MoveDown, cx); + editor.move_down(&MoveDown, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(1, "ab⋯e".len())] ); - view.move_left(&MoveLeft, cx); + editor.move_left(&MoveLeft, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(1, "ab⋯".len())] ); - view.move_left(&MoveLeft, cx); + editor.move_left(&MoveLeft, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(1, "ab".len())] ); - view.move_left(&MoveLeft, cx); + editor.move_left(&MoveLeft, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(1, "a".len())] ); - view.move_down(&MoveDown, cx); + editor.move_down(&MoveDown, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(2, "α".len())] ); - view.move_right(&MoveRight, cx); + editor.move_right(&MoveRight, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(2, "αβ".len())] ); - view.move_right(&MoveRight, cx); + editor.move_right(&MoveRight, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(2, "αβ⋯".len())] ); - view.move_right(&MoveRight, cx); + editor.move_right(&MoveRight, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(2, "αβ⋯ε".len())] ); - view.move_up(&MoveUp, cx); + editor.move_up(&MoveUp, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(1, "ab⋯e".len())] ); - view.move_down(&MoveDown, cx); + editor.move_down(&MoveDown, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(2, "αβ⋯ε".len())] ); - view.move_up(&MoveUp, cx); + editor.move_up(&MoveUp, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(1, "ab⋯e".len())] ); - view.move_up(&MoveUp, cx); + editor.move_up(&MoveUp, window, cx); assert_eq!( - view.selections.display_ranges(cx), - &[empty_range(0, "ⓐⓑ".len())] + editor.selections.display_ranges(cx), + &[empty_range(0, "🟥🟧".len())] ); - view.move_left(&MoveLeft, cx); + editor.move_left(&MoveLeft, window, cx); assert_eq!( - view.selections.display_ranges(cx), - &[empty_range(0, "ⓐ".len())] + editor.selections.display_ranges(cx), + &[empty_range(0, "🟥".len())] ); - view.move_left(&MoveLeft, cx); + editor.move_left(&MoveLeft, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(0, "".len())] ); }); @@ -1394,75 +1432,75 @@ fn test_move_cursor_multibyte(cx: &mut TestAppContext) { fn test_move_cursor_different_line_lengths(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcd\nαβγ\nabcd\nⓐⓑⓒⓓⓔ\n", cx); - build_editor(buffer.clone(), cx) + build_editor(buffer.clone(), window, cx) }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([empty_range(0, "ⓐⓑⓒⓓⓔ".len())]); }); // moving above start of document should move selection to start of document, // but the next move down should still be at the original goal_x - view.move_up(&MoveUp, cx); + editor.move_up(&MoveUp, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(0, "".len())] ); - view.move_down(&MoveDown, cx); + editor.move_down(&MoveDown, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(1, "abcd".len())] ); - view.move_down(&MoveDown, cx); + editor.move_down(&MoveDown, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(2, "αβγ".len())] ); - view.move_down(&MoveDown, cx); + editor.move_down(&MoveDown, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(3, "abcd".len())] ); - view.move_down(&MoveDown, cx); + editor.move_down(&MoveDown, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(4, "ⓐⓑⓒⓓⓔ".len())] ); // moving past end of document should not change goal_x - view.move_down(&MoveDown, cx); + editor.move_down(&MoveDown, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(5, "".len())] ); - view.move_down(&MoveDown, cx); + editor.move_down(&MoveDown, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(5, "".len())] ); - view.move_up(&MoveUp, cx); + editor.move_up(&MoveUp, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(4, "ⓐⓑⓒⓓⓔ".len())] ); - view.move_up(&MoveUp, cx); + editor.move_up(&MoveUp, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(3, "abcd".len())] ); - view.move_up(&MoveUp, cx); + editor.move_up(&MoveUp, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[empty_range(2, "αβγ".len())] ); }); @@ -1479,12 +1517,12 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { stop_at_soft_wraps: true, }; - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("abc\n def", cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1), DisplayPoint::new(DisplayRow(1), 4)..DisplayPoint::new(DisplayRow(1), 4), @@ -1492,10 +1530,10 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { }); }); - _ = view.update(cx, |view, cx| { - view.move_to_beginning_of_line(&move_to_beg, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.move_to_beginning_of_line(&move_to_beg, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[ DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0), DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(1), 2), @@ -1503,10 +1541,10 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { ); }); - _ = view.update(cx, |view, cx| { - view.move_to_beginning_of_line(&move_to_beg, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.move_to_beginning_of_line(&move_to_beg, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[ DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0), DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0), @@ -1514,10 +1552,10 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { ); }); - _ = view.update(cx, |view, cx| { - view.move_to_beginning_of_line(&move_to_beg, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.move_to_beginning_of_line(&move_to_beg, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[ DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0), DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(1), 2), @@ -1525,10 +1563,10 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { ); }); - _ = view.update(cx, |view, cx| { - view.move_to_end_of_line(&move_to_end, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.move_to_end_of_line(&move_to_end, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[ DisplayPoint::new(DisplayRow(0), 3)..DisplayPoint::new(DisplayRow(0), 3), DisplayPoint::new(DisplayRow(1), 5)..DisplayPoint::new(DisplayRow(1), 5), @@ -1537,10 +1575,10 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { }); // Moving to the end of line again is a no-op. - _ = view.update(cx, |view, cx| { - view.move_to_end_of_line(&move_to_end, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.move_to_end_of_line(&move_to_end, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[ DisplayPoint::new(DisplayRow(0), 3)..DisplayPoint::new(DisplayRow(0), 3), DisplayPoint::new(DisplayRow(1), 5)..DisplayPoint::new(DisplayRow(1), 5), @@ -1548,16 +1586,17 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { ); }); - _ = view.update(cx, |view, cx| { - view.move_left(&MoveLeft, cx); - view.select_to_beginning_of_line( + _ = editor.update(cx, |editor, window, cx| { + editor.move_left(&MoveLeft, window, cx); + editor.select_to_beginning_of_line( &SelectToBeginningOfLine { stop_at_soft_wraps: true, }, + window, cx, ); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[ DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 0), DisplayPoint::new(DisplayRow(1), 4)..DisplayPoint::new(DisplayRow(1), 2), @@ -1565,15 +1604,16 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { ); }); - _ = view.update(cx, |view, cx| { - view.select_to_beginning_of_line( + _ = editor.update(cx, |editor, window, cx| { + editor.select_to_beginning_of_line( &SelectToBeginningOfLine { stop_at_soft_wraps: true, }, + window, cx, ); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[ DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 0), DisplayPoint::new(DisplayRow(1), 4)..DisplayPoint::new(DisplayRow(1), 0), @@ -1581,15 +1621,16 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { ); }); - _ = view.update(cx, |view, cx| { - view.select_to_beginning_of_line( + _ = editor.update(cx, |editor, window, cx| { + editor.select_to_beginning_of_line( &SelectToBeginningOfLine { stop_at_soft_wraps: true, }, + window, cx, ); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[ DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 0), DisplayPoint::new(DisplayRow(1), 4)..DisplayPoint::new(DisplayRow(1), 2), @@ -1597,15 +1638,16 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { ); }); - _ = view.update(cx, |view, cx| { - view.select_to_end_of_line( + _ = editor.update(cx, |editor, window, cx| { + editor.select_to_end_of_line( &SelectToEndOfLine { stop_at_soft_wraps: true, }, + window, cx, ); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[ DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 3), DisplayPoint::new(DisplayRow(1), 4)..DisplayPoint::new(DisplayRow(1), 5), @@ -1613,11 +1655,11 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { ); }); - _ = view.update(cx, |view, cx| { - view.delete_to_end_of_line(&DeleteToEndOfLine, cx); - assert_eq!(view.display_text(cx), "ab\n de"); + _ = editor.update(cx, |editor, window, cx| { + editor.delete_to_end_of_line(&DeleteToEndOfLine, window, cx); + assert_eq!(editor.display_text(cx), "ab\n de"); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[ DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), DisplayPoint::new(DisplayRow(1), 4)..DisplayPoint::new(DisplayRow(1), 4), @@ -1625,11 +1667,11 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { ); }); - _ = view.update(cx, |view, cx| { - view.delete_to_beginning_of_line(&DeleteToBeginningOfLine, cx); - assert_eq!(view.display_text(cx), "\n"); + _ = editor.update(cx, |editor, window, cx| { + editor.delete_to_beginning_of_line(&DeleteToBeginningOfLine, window, cx); + assert_eq!(editor.display_text(cx), "\n"); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[ DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0), DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0), @@ -1649,13 +1691,13 @@ fn test_beginning_end_of_line_ignore_soft_wrap(cx: &mut TestAppContext) { stop_at_soft_wraps: false, }; - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("thequickbrownfox\njumpedoverthelazydogs", cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.set_wrap_width(Some(140.0.into()), cx); + _ = editor.update(cx, |editor, window, cx| { + editor.set_wrap_width(Some(140.0.into()), cx); // We expect the following lines after wrapping // ``` @@ -1666,34 +1708,34 @@ fn test_beginning_end_of_line_ignore_soft_wrap(cx: &mut TestAppContext) { // The final `gs` was soft-wrapped onto a new line. assert_eq!( "thequickbrownfox\njumpedoverthelaz\nydogs", - view.display_text(cx), + editor.display_text(cx), ); // First, let's assert behavior on the first line, that was not soft-wrapped. // Start the cursor at the `k` on the first line - view.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(0), 7)..DisplayPoint::new(DisplayRow(0), 7) ]); }); // Moving to the beginning of the line should put us at the beginning of the line. - view.move_to_beginning_of_line(&move_to_beg, cx); + editor.move_to_beginning_of_line(&move_to_beg, window, cx); assert_eq!( vec![DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0),], - view.selections.display_ranges(cx) + editor.selections.display_ranges(cx) ); // Moving to the end of the line should put us at the end of the line. - view.move_to_end_of_line(&move_to_end, cx); + editor.move_to_end_of_line(&move_to_end, window, cx); assert_eq!( vec![DisplayPoint::new(DisplayRow(0), 16)..DisplayPoint::new(DisplayRow(0), 16),], - view.selections.display_ranges(cx) + editor.selections.display_ranges(cx) ); // Now, let's assert behavior on the second line, that ended up being soft-wrapped. // Start the cursor at the last line (`y` that was wrapped to a new line) - view.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(2), 0)..DisplayPoint::new(DisplayRow(2), 0) ]); @@ -1701,32 +1743,32 @@ fn test_beginning_end_of_line_ignore_soft_wrap(cx: &mut TestAppContext) { // Moving to the beginning of the line should put us at the start of the second line of // display text, i.e., the `j`. - view.move_to_beginning_of_line(&move_to_beg, cx); + editor.move_to_beginning_of_line(&move_to_beg, window, cx); assert_eq!( vec![DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0),], - view.selections.display_ranges(cx) + editor.selections.display_ranges(cx) ); // Moving to the beginning of the line again should be a no-op. - view.move_to_beginning_of_line(&move_to_beg, cx); + editor.move_to_beginning_of_line(&move_to_beg, window, cx); assert_eq!( vec![DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0),], - view.selections.display_ranges(cx) + editor.selections.display_ranges(cx) ); // Moving to the end of the line should put us right after the `s` that was soft-wrapped to the // next display line. - view.move_to_end_of_line(&move_to_end, cx); + editor.move_to_end_of_line(&move_to_end, window, cx); assert_eq!( vec![DisplayPoint::new(DisplayRow(2), 5)..DisplayPoint::new(DisplayRow(2), 5),], - view.selections.display_ranges(cx) + editor.selections.display_ranges(cx) ); // Moving to the end of the line again should be a no-op. - view.move_to_end_of_line(&move_to_end, cx); + editor.move_to_end_of_line(&move_to_end, window, cx); assert_eq!( vec![DisplayPoint::new(DisplayRow(2), 5)..DisplayPoint::new(DisplayRow(2), 5),], - view.selections.display_ranges(cx) + editor.selections.display_ranges(cx) ); }); } @@ -1735,51 +1777,63 @@ fn test_beginning_end_of_line_ignore_soft_wrap(cx: &mut TestAppContext) { fn test_prev_next_word_boundary(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("use std::str::{foo, bar}\n\n {baz.qux()}", cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(0), 11)..DisplayPoint::new(DisplayRow(0), 11), DisplayPoint::new(DisplayRow(2), 4)..DisplayPoint::new(DisplayRow(2), 4), ]) }); - view.move_to_previous_word_start(&MoveToPreviousWordStart, cx); - assert_selection_ranges("use std::ˇstr::{foo, bar}\n\n {ˇbaz.qux()}", view, cx); + editor.move_to_previous_word_start(&MoveToPreviousWordStart, window, cx); + assert_selection_ranges("use std::ˇstr::{foo, bar}\n\n {ˇbaz.qux()}", editor, cx); - view.move_to_previous_word_start(&MoveToPreviousWordStart, cx); - assert_selection_ranges("use stdˇ::str::{foo, bar}\n\n ˇ{baz.qux()}", view, cx); + editor.move_to_previous_word_start(&MoveToPreviousWordStart, window, cx); + assert_selection_ranges("use stdˇ::str::{foo, bar}\n\n ˇ{baz.qux()}", editor, cx); - view.move_to_previous_word_start(&MoveToPreviousWordStart, cx); - assert_selection_ranges("use ˇstd::str::{foo, bar}\n\nˇ {baz.qux()}", view, cx); + editor.move_to_previous_word_start(&MoveToPreviousWordStart, window, cx); + assert_selection_ranges("use ˇstd::str::{foo, bar}\n\nˇ {baz.qux()}", editor, cx); - view.move_to_previous_word_start(&MoveToPreviousWordStart, cx); - assert_selection_ranges("ˇuse std::str::{foo, bar}\nˇ\n {baz.qux()}", view, cx); + editor.move_to_previous_word_start(&MoveToPreviousWordStart, window, cx); + assert_selection_ranges("ˇuse std::str::{foo, bar}\nˇ\n {baz.qux()}", editor, cx); - view.move_to_previous_word_start(&MoveToPreviousWordStart, cx); - assert_selection_ranges("ˇuse std::str::{foo, barˇ}\n\n {baz.qux()}", view, cx); + editor.move_to_previous_word_start(&MoveToPreviousWordStart, window, cx); + assert_selection_ranges("ˇuse std::str::{foo, barˇ}\n\n {baz.qux()}", editor, cx); - view.move_to_next_word_end(&MoveToNextWordEnd, cx); - assert_selection_ranges("useˇ std::str::{foo, bar}ˇ\n\n {baz.qux()}", view, cx); + editor.move_to_next_word_end(&MoveToNextWordEnd, window, cx); + assert_selection_ranges("useˇ std::str::{foo, bar}ˇ\n\n {baz.qux()}", editor, cx); - view.move_to_next_word_end(&MoveToNextWordEnd, cx); - assert_selection_ranges("use stdˇ::str::{foo, bar}\nˇ\n {baz.qux()}", view, cx); + editor.move_to_next_word_end(&MoveToNextWordEnd, window, cx); + assert_selection_ranges("use stdˇ::str::{foo, bar}\nˇ\n {baz.qux()}", editor, cx); - view.move_to_next_word_end(&MoveToNextWordEnd, cx); - assert_selection_ranges("use std::ˇstr::{foo, bar}\n\n {ˇbaz.qux()}", view, cx); + editor.move_to_next_word_end(&MoveToNextWordEnd, window, cx); + assert_selection_ranges("use std::ˇstr::{foo, bar}\n\n {ˇbaz.qux()}", editor, cx); - view.move_right(&MoveRight, cx); - view.select_to_previous_word_start(&SelectToPreviousWordStart, cx); - assert_selection_ranges("use std::«ˇs»tr::{foo, bar}\n\n {«ˇb»az.qux()}", view, cx); + editor.move_right(&MoveRight, window, cx); + editor.select_to_previous_word_start(&SelectToPreviousWordStart, window, cx); + assert_selection_ranges( + "use std::«ˇs»tr::{foo, bar}\n\n {«ˇb»az.qux()}", + editor, + cx, + ); - view.select_to_previous_word_start(&SelectToPreviousWordStart, cx); - assert_selection_ranges("use std«ˇ::s»tr::{foo, bar}\n\n «ˇ{b»az.qux()}", view, cx); + editor.select_to_previous_word_start(&SelectToPreviousWordStart, window, cx); + assert_selection_ranges( + "use std«ˇ::s»tr::{foo, bar}\n\n «ˇ{b»az.qux()}", + editor, + cx, + ); - view.select_to_next_word_end(&SelectToNextWordEnd, cx); - assert_selection_ranges("use std::«ˇs»tr::{foo, bar}\n\n {«ˇb»az.qux()}", view, cx); + editor.select_to_next_word_end(&SelectToNextWordEnd, window, cx); + assert_selection_ranges( + "use std::«ˇs»tr::{foo, bar}\n\n {«ˇb»az.qux()}", + editor, + cx, + ); }); } @@ -1787,57 +1841,57 @@ fn test_prev_next_word_boundary(cx: &mut TestAppContext) { fn test_prev_next_word_bounds_with_soft_wrap(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("use one::{\n two::three::four::five\n};", cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.set_wrap_width(Some(140.0.into()), cx); + _ = editor.update(cx, |editor, window, cx| { + editor.set_wrap_width(Some(140.0.into()), cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), "use one::{\n two::three::\n four::five\n};" ); - view.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(1), 7)..DisplayPoint::new(DisplayRow(1), 7) ]); }); - view.move_to_next_word_end(&MoveToNextWordEnd, cx); + editor.move_to_next_word_end(&MoveToNextWordEnd, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(1), 9)..DisplayPoint::new(DisplayRow(1), 9)] ); - view.move_to_next_word_end(&MoveToNextWordEnd, cx); + editor.move_to_next_word_end(&MoveToNextWordEnd, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(1), 14)..DisplayPoint::new(DisplayRow(1), 14)] ); - view.move_to_next_word_end(&MoveToNextWordEnd, cx); + editor.move_to_next_word_end(&MoveToNextWordEnd, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(2), 4)..DisplayPoint::new(DisplayRow(2), 4)] ); - view.move_to_next_word_end(&MoveToNextWordEnd, cx); + editor.move_to_next_word_end(&MoveToNextWordEnd, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(2), 8)..DisplayPoint::new(DisplayRow(2), 8)] ); - view.move_to_previous_word_start(&MoveToPreviousWordStart, cx); + editor.move_to_previous_word_start(&MoveToPreviousWordStart, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(2), 4)..DisplayPoint::new(DisplayRow(2), 4)] ); - view.move_to_previous_word_start(&MoveToPreviousWordStart, cx); + editor.move_to_previous_word_start(&MoveToPreviousWordStart, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(1), 14)..DisplayPoint::new(DisplayRow(1), 14)] ); }); @@ -1848,12 +1902,12 @@ async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppCon init_test(cx, |_| {}); let mut cx = EditorTestContext::new(cx).await; - let line_height = cx.editor(|editor, cx| { + let line_height = cx.editor(|editor, window, _| { editor .style() .unwrap() .text - .line_height_in_pixels(cx.rem_size()) + .line_height_in_pixels(window.rem_size()) }); cx.simulate_window_resize(cx.window, size(px(100.), 4. * line_height)); @@ -1869,7 +1923,9 @@ async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppCon .unindent(), ); - cx.update_editor(|editor, cx| editor.move_to_end_of_paragraph(&MoveToEndOfParagraph, cx)); + cx.update_editor(|editor, window, cx| { + editor.move_to_end_of_paragraph(&MoveToEndOfParagraph, window, cx) + }); cx.assert_editor_state( &r#"one two @@ -1882,7 +1938,9 @@ async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppCon .unindent(), ); - cx.update_editor(|editor, cx| editor.move_to_end_of_paragraph(&MoveToEndOfParagraph, cx)); + cx.update_editor(|editor, window, cx| { + editor.move_to_end_of_paragraph(&MoveToEndOfParagraph, window, cx) + }); cx.assert_editor_state( &r#"one two @@ -1895,7 +1953,9 @@ async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppCon .unindent(), ); - cx.update_editor(|editor, cx| editor.move_to_end_of_paragraph(&MoveToEndOfParagraph, cx)); + cx.update_editor(|editor, window, cx| { + editor.move_to_end_of_paragraph(&MoveToEndOfParagraph, window, cx) + }); cx.assert_editor_state( &r#"one two @@ -1908,7 +1968,9 @@ async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppCon .unindent(), ); - cx.update_editor(|editor, cx| editor.move_to_start_of_paragraph(&MoveToStartOfParagraph, cx)); + cx.update_editor(|editor, window, cx| { + editor.move_to_start_of_paragraph(&MoveToStartOfParagraph, window, cx) + }); cx.assert_editor_state( &r#"one two @@ -1921,7 +1983,9 @@ async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppCon .unindent(), ); - cx.update_editor(|editor, cx| editor.move_to_start_of_paragraph(&MoveToStartOfParagraph, cx)); + cx.update_editor(|editor, window, cx| { + editor.move_to_start_of_paragraph(&MoveToStartOfParagraph, window, cx) + }); cx.assert_editor_state( &r#"one two @@ -1934,7 +1998,9 @@ async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppCon .unindent(), ); - cx.update_editor(|editor, cx| editor.move_to_start_of_paragraph(&MoveToStartOfParagraph, cx)); + cx.update_editor(|editor, window, cx| { + editor.move_to_start_of_paragraph(&MoveToStartOfParagraph, window, cx) + }); cx.assert_editor_state( &r#"ˇone two @@ -1952,12 +2018,12 @@ async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppCon async fn test_scroll_page_up_page_down(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); let mut cx = EditorTestContext::new(cx).await; - let line_height = cx.editor(|editor, cx| { + let line_height = cx.editor(|editor, window, _| { editor .style() .unwrap() .text - .line_height_in_pixels(cx.rem_size()) + .line_height_in_pixels(window.rem_size()) }); let window = cx.window; cx.simulate_window_resize(window, size(px(1000.), 4. * line_height + px(0.5))); @@ -1976,35 +2042,35 @@ async fn test_scroll_page_up_page_down(cx: &mut gpui::TestAppContext) { "#, ); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, window, cx| { assert_eq!( - editor.snapshot(cx).scroll_position(), + editor.snapshot(window, cx).scroll_position(), gpui::Point::new(0., 0.) ); - editor.scroll_screen(&ScrollAmount::Page(1.), cx); + editor.scroll_screen(&ScrollAmount::Page(1.), window, cx); assert_eq!( - editor.snapshot(cx).scroll_position(), + editor.snapshot(window, cx).scroll_position(), gpui::Point::new(0., 3.) ); - editor.scroll_screen(&ScrollAmount::Page(1.), cx); + editor.scroll_screen(&ScrollAmount::Page(1.), window, cx); assert_eq!( - editor.snapshot(cx).scroll_position(), + editor.snapshot(window, cx).scroll_position(), gpui::Point::new(0., 6.) ); - editor.scroll_screen(&ScrollAmount::Page(-1.), cx); + editor.scroll_screen(&ScrollAmount::Page(-1.), window, cx); assert_eq!( - editor.snapshot(cx).scroll_position(), + editor.snapshot(window, cx).scroll_position(), gpui::Point::new(0., 3.) ); - editor.scroll_screen(&ScrollAmount::Page(-0.5), cx); + editor.scroll_screen(&ScrollAmount::Page(-0.5), window, cx); assert_eq!( - editor.snapshot(cx).scroll_position(), + editor.snapshot(window, cx).scroll_position(), gpui::Point::new(0., 1.) ); - editor.scroll_screen(&ScrollAmount::Page(0.5), cx); + editor.scroll_screen(&ScrollAmount::Page(0.5), window, cx); assert_eq!( - editor.snapshot(cx).scroll_position(), + editor.snapshot(window, cx).scroll_position(), gpui::Point::new(0., 3.) ); }); @@ -2015,13 +2081,13 @@ async fn test_autoscroll(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); let mut cx = EditorTestContext::new(cx).await; - let line_height = cx.update_editor(|editor, cx| { + let line_height = cx.update_editor(|editor, window, cx| { editor.set_vertical_scroll_margin(2, cx); editor .style() .unwrap() .text - .line_height_in_pixels(cx.rem_size()) + .line_height_in_pixels(window.rem_size()) }); let window = cx.window; cx.simulate_window_resize(window, size(px(1000.), 6. * line_height)); @@ -2039,9 +2105,9 @@ async fn test_autoscroll(cx: &mut gpui::TestAppContext) { ten "#, ); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, window, cx| { assert_eq!( - editor.snapshot(cx).scroll_position(), + editor.snapshot(window, cx).scroll_position(), gpui::Point::new(0., 0.0) ); }); @@ -2049,45 +2115,45 @@ async fn test_autoscroll(cx: &mut gpui::TestAppContext) { // Add a cursor below the visible area. Since both cursors cannot fit // on screen, the editor autoscrolls to reveal the newest cursor, and // allows the vertical scroll margin below that cursor. - cx.update_editor(|editor, cx| { - editor.change_selections(Some(Autoscroll::fit()), cx, |selections| { + cx.update_editor(|editor, window, cx| { + editor.change_selections(Some(Autoscroll::fit()), window, cx, |selections| { selections.select_ranges([ Point::new(0, 0)..Point::new(0, 0), Point::new(6, 0)..Point::new(6, 0), ]); }) }); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, window, cx| { assert_eq!( - editor.snapshot(cx).scroll_position(), + editor.snapshot(window, cx).scroll_position(), gpui::Point::new(0., 3.0) ); }); // Move down. The editor cursor scrolls down to track the newest cursor. - cx.update_editor(|editor, cx| { - editor.move_down(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.move_down(&Default::default(), window, cx); }); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, window, cx| { assert_eq!( - editor.snapshot(cx).scroll_position(), + editor.snapshot(window, cx).scroll_position(), gpui::Point::new(0., 4.0) ); }); // Add a cursor above the visible area. Since both cursors fit on screen, // the editor scrolls to show both. - cx.update_editor(|editor, cx| { - editor.change_selections(Some(Autoscroll::fit()), cx, |selections| { + cx.update_editor(|editor, window, cx| { + editor.change_selections(Some(Autoscroll::fit()), window, cx, |selections| { selections.select_ranges([ Point::new(1, 0)..Point::new(1, 0), Point::new(6, 0)..Point::new(6, 0), ]); }) }); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, window, cx| { assert_eq!( - editor.snapshot(cx).scroll_position(), + editor.snapshot(window, cx).scroll_position(), gpui::Point::new(0., 1.0) ); }); @@ -2098,12 +2164,12 @@ async fn test_move_page_up_page_down(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); let mut cx = EditorTestContext::new(cx).await; - let line_height = cx.editor(|editor, cx| { + let line_height = cx.editor(|editor, window, _cx| { editor .style() .unwrap() .text - .line_height_in_pixels(cx.rem_size()) + .line_height_in_pixels(window.rem_size()) }); let window = cx.window; cx.simulate_window_resize(window, size(px(100.), 4. * line_height)); @@ -2123,7 +2189,9 @@ async fn test_move_page_up_page_down(cx: &mut gpui::TestAppContext) { .unindent(), ); - cx.update_editor(|editor, cx| editor.move_page_down(&MovePageDown::default(), cx)); + cx.update_editor(|editor, window, cx| { + editor.move_page_down(&MovePageDown::default(), window, cx) + }); cx.assert_editor_state( &r#" one @@ -2140,7 +2208,9 @@ async fn test_move_page_up_page_down(cx: &mut gpui::TestAppContext) { .unindent(), ); - cx.update_editor(|editor, cx| editor.move_page_down(&MovePageDown::default(), cx)); + cx.update_editor(|editor, window, cx| { + editor.move_page_down(&MovePageDown::default(), window, cx) + }); cx.assert_editor_state( &r#" one @@ -2157,7 +2227,7 @@ async fn test_move_page_up_page_down(cx: &mut gpui::TestAppContext) { .unindent(), ); - cx.update_editor(|editor, cx| editor.move_page_up(&MovePageUp::default(), cx)); + cx.update_editor(|editor, window, cx| editor.move_page_up(&MovePageUp::default(), window, cx)); cx.assert_editor_state( &r#" one @@ -2174,7 +2244,7 @@ async fn test_move_page_up_page_down(cx: &mut gpui::TestAppContext) { .unindent(), ); - cx.update_editor(|editor, cx| editor.move_page_up(&MovePageUp::default(), cx)); + cx.update_editor(|editor, window, cx| editor.move_page_up(&MovePageUp::default(), window, cx)); cx.assert_editor_state( &r#" ˇone @@ -2192,10 +2262,10 @@ async fn test_move_page_up_page_down(cx: &mut gpui::TestAppContext) { ); // Test select collapsing - cx.update_editor(|editor, cx| { - editor.move_page_down(&MovePageDown::default(), cx); - editor.move_page_down(&MovePageDown::default(), cx); - editor.move_page_down(&MovePageDown::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.move_page_down(&MovePageDown::default(), window, cx); + editor.move_page_down(&MovePageDown::default(), window, cx); + editor.move_page_down(&MovePageDown::default(), window, cx); }); cx.assert_editor_state( &r#" @@ -2219,8 +2289,8 @@ async fn test_delete_to_beginning_of_line(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); let mut cx = EditorTestContext::new(cx).await; cx.set_state("one «two threeˇ» four"); - cx.update_editor(|editor, cx| { - editor.delete_to_beginning_of_line(&DeleteToBeginningOfLine, cx); + cx.update_editor(|editor, window, cx| { + editor.delete_to_beginning_of_line(&DeleteToBeginningOfLine, window, cx); assert_eq!(editor.text(cx), " four"); }); } @@ -2229,13 +2299,13 @@ async fn test_delete_to_beginning_of_line(cx: &mut gpui::TestAppContext) { fn test_delete_to_word_boundary(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("one two three four", cx); - build_editor(buffer.clone(), cx) + build_editor(buffer.clone(), window, cx) }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ // an empty selection - the preceding word fragment is deleted DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), @@ -2243,17 +2313,18 @@ fn test_delete_to_word_boundary(cx: &mut TestAppContext) { DisplayPoint::new(DisplayRow(0), 9)..DisplayPoint::new(DisplayRow(0), 12), ]) }); - view.delete_to_previous_word_start( + editor.delete_to_previous_word_start( &DeleteToPreviousWordStart { ignore_newlines: false, }, + window, cx, ); - assert_eq!(view.buffer.read(cx).read(cx).text(), "e two te four"); + assert_eq!(editor.buffer.read(cx).read(cx).text(), "e two te four"); }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ // an empty selection - the following word fragment is deleted DisplayPoint::new(DisplayRow(0), 3)..DisplayPoint::new(DisplayRow(0), 3), @@ -2261,13 +2332,14 @@ fn test_delete_to_word_boundary(cx: &mut TestAppContext) { DisplayPoint::new(DisplayRow(0), 9)..DisplayPoint::new(DisplayRow(0), 10), ]) }); - view.delete_to_next_word_end( + editor.delete_to_next_word_end( &DeleteToNextWordEnd { ignore_newlines: false, }, + window, cx, ); - assert_eq!(view.buffer.read(cx).read(cx).text(), "e t te our"); + assert_eq!(editor.buffer.read(cx).read(cx).text(), "e t te our"); }); } @@ -2275,9 +2347,9 @@ fn test_delete_to_word_boundary(cx: &mut TestAppContext) { fn test_delete_to_previous_word_start_or_newline(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("one\n2\nthree\n4", cx); - build_editor(buffer.clone(), cx) + build_editor(buffer.clone(), window, cx) }); let del_to_prev_word_start = DeleteToPreviousWordStart { ignore_newlines: false, @@ -2286,24 +2358,24 @@ fn test_delete_to_previous_word_start_or_newline(cx: &mut TestAppContext) { ignore_newlines: true, }; - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(3), 1)..DisplayPoint::new(DisplayRow(3), 1) ]) }); - view.delete_to_previous_word_start(&del_to_prev_word_start, cx); - assert_eq!(view.buffer.read(cx).read(cx).text(), "one\n2\nthree\n"); - view.delete_to_previous_word_start(&del_to_prev_word_start, cx); - assert_eq!(view.buffer.read(cx).read(cx).text(), "one\n2\nthree"); - view.delete_to_previous_word_start(&del_to_prev_word_start, cx); - assert_eq!(view.buffer.read(cx).read(cx).text(), "one\n2\n"); - view.delete_to_previous_word_start(&del_to_prev_word_start, cx); - assert_eq!(view.buffer.read(cx).read(cx).text(), "one\n2"); - view.delete_to_previous_word_start(&del_to_prev_word_start_ignore_newlines, cx); - assert_eq!(view.buffer.read(cx).read(cx).text(), "one\n"); - view.delete_to_previous_word_start(&del_to_prev_word_start_ignore_newlines, cx); - assert_eq!(view.buffer.read(cx).read(cx).text(), ""); + editor.delete_to_previous_word_start(&del_to_prev_word_start, window, cx); + assert_eq!(editor.buffer.read(cx).read(cx).text(), "one\n2\nthree\n"); + editor.delete_to_previous_word_start(&del_to_prev_word_start, window, cx); + assert_eq!(editor.buffer.read(cx).read(cx).text(), "one\n2\nthree"); + editor.delete_to_previous_word_start(&del_to_prev_word_start, window, cx); + assert_eq!(editor.buffer.read(cx).read(cx).text(), "one\n2\n"); + editor.delete_to_previous_word_start(&del_to_prev_word_start, window, cx); + assert_eq!(editor.buffer.read(cx).read(cx).text(), "one\n2"); + editor.delete_to_previous_word_start(&del_to_prev_word_start_ignore_newlines, window, cx); + assert_eq!(editor.buffer.read(cx).read(cx).text(), "one\n"); + editor.delete_to_previous_word_start(&del_to_prev_word_start_ignore_newlines, window, cx); + assert_eq!(editor.buffer.read(cx).read(cx).text(), ""); }); } @@ -2311,9 +2383,9 @@ fn test_delete_to_previous_word_start_or_newline(cx: &mut TestAppContext) { fn test_delete_to_next_word_end_or_newline(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("\none\n two\nthree\n four", cx); - build_editor(buffer.clone(), cx) + build_editor(buffer.clone(), window, cx) }); let del_to_next_word_end = DeleteToNextWordEnd { ignore_newlines: false, @@ -2322,30 +2394,33 @@ fn test_delete_to_next_word_end_or_newline(cx: &mut TestAppContext) { ignore_newlines: true, }; - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0) ]) }); - view.delete_to_next_word_end(&del_to_next_word_end, cx); + editor.delete_to_next_word_end(&del_to_next_word_end, window, cx); assert_eq!( - view.buffer.read(cx).read(cx).text(), + editor.buffer.read(cx).read(cx).text(), "one\n two\nthree\n four" ); - view.delete_to_next_word_end(&del_to_next_word_end, cx); + editor.delete_to_next_word_end(&del_to_next_word_end, window, cx); assert_eq!( - view.buffer.read(cx).read(cx).text(), + editor.buffer.read(cx).read(cx).text(), "\n two\nthree\n four" ); - view.delete_to_next_word_end(&del_to_next_word_end, cx); - assert_eq!(view.buffer.read(cx).read(cx).text(), "two\nthree\n four"); - view.delete_to_next_word_end(&del_to_next_word_end, cx); - assert_eq!(view.buffer.read(cx).read(cx).text(), "\nthree\n four"); - view.delete_to_next_word_end(&del_to_next_word_end_ignore_newlines, cx); - assert_eq!(view.buffer.read(cx).read(cx).text(), "\n four"); - view.delete_to_next_word_end(&del_to_next_word_end_ignore_newlines, cx); - assert_eq!(view.buffer.read(cx).read(cx).text(), ""); + editor.delete_to_next_word_end(&del_to_next_word_end, window, cx); + assert_eq!( + editor.buffer.read(cx).read(cx).text(), + "two\nthree\n four" + ); + editor.delete_to_next_word_end(&del_to_next_word_end, window, cx); + assert_eq!(editor.buffer.read(cx).read(cx).text(), "\nthree\n four"); + editor.delete_to_next_word_end(&del_to_next_word_end_ignore_newlines, window, cx); + assert_eq!(editor.buffer.read(cx).read(cx).text(), "\n four"); + editor.delete_to_next_word_end(&del_to_next_word_end_ignore_newlines, window, cx); + assert_eq!(editor.buffer.read(cx).read(cx).text(), ""); }); } @@ -2353,13 +2428,13 @@ fn test_delete_to_next_word_end_or_newline(cx: &mut TestAppContext) { fn test_newline(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("aaaa\n bbbb\n", cx); - build_editor(buffer.clone(), cx) + build_editor(buffer.clone(), window, cx) }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(1), 2), @@ -2367,8 +2442,8 @@ fn test_newline(cx: &mut TestAppContext) { ]) }); - view.newline(&Newline, cx); - assert_eq!(view.text(cx), "aa\naa\n \n bb\n bb\n"); + editor.newline(&Newline, window, cx); + assert_eq!(editor.text(cx), "aa\naa\n \n bb\n bb\n"); }); } @@ -2376,7 +2451,7 @@ fn test_newline(cx: &mut TestAppContext) { fn test_newline_with_old_selections(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let editor = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple( " a @@ -2391,8 +2466,8 @@ fn test_newline_with_old_selections(cx: &mut TestAppContext) { .as_str(), cx, ); - let mut editor = build_editor(buffer.clone(), cx); - editor.change_selections(None, cx, |s| { + let mut editor = build_editor(buffer.clone(), window, cx); + editor.change_selections(None, window, cx, |s| { s.select_ranges([ Point::new(2, 4)..Point::new(2, 5), Point::new(5, 4)..Point::new(5, 5), @@ -2401,7 +2476,7 @@ fn test_newline_with_old_selections(cx: &mut TestAppContext) { editor }); - _ = editor.update(cx, |editor, cx| { + _ = editor.update(cx, |editor, window, cx| { // Edit the buffer directly, deleting ranges surrounding the editor's selections editor.buffer.update(cx, |buffer, cx| { buffer.edit( @@ -2430,7 +2505,7 @@ fn test_newline_with_old_selections(cx: &mut TestAppContext) { ], ); - editor.newline(&Newline, cx); + editor.newline(&Newline, window, cx); assert_eq!( editor.text(cx), " @@ -2480,7 +2555,7 @@ async fn test_newline_above(cx: &mut gpui::TestAppContext) { ˇ);ˇ "}); - cx.update_editor(|e, cx| e.newline_above(&NewlineAbove, cx)); + cx.update_editor(|e, window, cx| e.newline_above(&NewlineAbove, window, cx)); cx.assert_editor_state(indoc! {" ˇ const a: A = ( @@ -2528,7 +2603,7 @@ async fn test_newline_below(cx: &mut gpui::TestAppContext) { ˇ);ˇ "}); - cx.update_editor(|e, cx| e.newline_below(&NewlineBelow, cx)); + cx.update_editor(|e, window, cx| e.newline_below(&NewlineBelow, window, cx)); cx.assert_editor_state(indoc! {" const a: A = ( ˇ @@ -2570,7 +2645,7 @@ async fn test_newline_comments(cx: &mut gpui::TestAppContext) { // Fooˇ "}); - cx.update_editor(|e, cx| e.newline(&Newline, cx)); + cx.update_editor(|e, window, cx| e.newline(&Newline, window, cx)); cx.assert_editor_state(indoc! {" // Foo //ˇ @@ -2579,7 +2654,7 @@ async fn test_newline_comments(cx: &mut gpui::TestAppContext) { cx.set_state(indoc! {" ˇ// Foo "}); - cx.update_editor(|e, cx| e.newline(&Newline, cx)); + cx.update_editor(|e, window, cx| e.newline(&Newline, window, cx)); cx.assert_editor_state(indoc! {" ˇ// Foo @@ -2593,7 +2668,7 @@ async fn test_newline_comments(cx: &mut gpui::TestAppContext) { cx.set_state(indoc! {" // Fooˇ "}); - cx.update_editor(|e, cx| e.newline(&Newline, cx)); + cx.update_editor(|e, window, cx| e.newline(&Newline, window, cx)); cx.assert_editor_state(indoc! {" // Foo ˇ @@ -2604,14 +2679,16 @@ async fn test_newline_comments(cx: &mut gpui::TestAppContext) { fn test_insert_with_old_selections(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let editor = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("a( X ), b( Y ), c( Z )", cx); - let mut editor = build_editor(buffer.clone(), cx); - editor.change_selections(None, cx, |s| s.select_ranges([3..4, 11..12, 19..20])); + let mut editor = build_editor(buffer.clone(), window, cx); + editor.change_selections(None, window, cx, |s| { + s.select_ranges([3..4, 11..12, 19..20]) + }); editor }); - _ = editor.update(cx, |editor, cx| { + _ = editor.update(cx, |editor, window, cx| { // Edit the buffer directly, deleting ranges surrounding the editor's selections editor.buffer.update(cx, |buffer, cx| { buffer.edit([(2..5, ""), (10..13, ""), (18..21, "")], None, cx); @@ -2619,7 +2696,7 @@ fn test_insert_with_old_selections(cx: &mut TestAppContext) { }); assert_eq!(editor.selections.ranges(cx), &[2..2, 7..7, 12..12],); - editor.insert("Z", cx); + editor.insert("Z", window, cx); assert_eq!(editor.text(cx), "a(Z), b(Z), c(Z)"); // The selections are moved after the inserted characters @@ -2639,7 +2716,7 @@ async fn test_tab(cx: &mut gpui::TestAppContext) { ˇ🏀ˇ🏀ˇefg dˇ "}); - cx.update_editor(|e, cx| e.tab(&Tab, cx)); + cx.update_editor(|e, window, cx| e.tab(&Tab, window, cx)); cx.assert_editor_state(indoc! {" ˇab ˇc ˇ🏀 ˇ🏀 ˇefg @@ -2650,7 +2727,7 @@ async fn test_tab(cx: &mut gpui::TestAppContext) { a «🏀ˇ»🏀«🏀ˇ»🏀«🏀ˇ» "}); - cx.update_editor(|e, cx| e.tab(&Tab, cx)); + cx.update_editor(|e, window, cx| e.tab(&Tab, window, cx)); cx.assert_editor_state(indoc! {" a «🏀ˇ»🏀«🏀ˇ»🏀«🏀ˇ» @@ -2686,7 +2763,7 @@ async fn test_tab_in_leading_whitespace_auto_indents_lines(cx: &mut gpui::TestAp ˇ ) ); "}); - cx.update_editor(|e, cx| e.tab(&Tab, cx)); + cx.update_editor(|e, window, cx| e.tab(&Tab, window, cx)); cx.assert_editor_state(indoc! {" ˇ const a: B = ( @@ -2707,7 +2784,7 @@ async fn test_tab_in_leading_whitespace_auto_indents_lines(cx: &mut gpui::TestAp ˇ ) ); "}); - cx.update_editor(|e, cx| e.tab(&Tab, cx)); + cx.update_editor(|e, window, cx| e.tab(&Tab, window, cx)); cx.assert_editor_state(indoc! {" const a: B = ( c( @@ -2742,7 +2819,7 @@ async fn test_tab_with_mixed_whitespace(cx: &mut gpui::TestAppContext) { } "}); - cx.update_editor(|e, cx| e.tab(&Tab, cx)); + cx.update_editor(|e, window, cx| e.tab(&Tab, window, cx)); cx.assert_editor_state(indoc! {" fn a() { if b { @@ -2765,14 +2842,14 @@ async fn test_indent_outdent(cx: &mut gpui::TestAppContext) { three four "}); - cx.update_editor(|e, cx| e.tab(&Tab, cx)); + cx.update_editor(|e, window, cx| e.tab(&Tab, window, cx)); cx.assert_editor_state(indoc! {" «oneˇ» «twoˇ» three four "}); - cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx)); + cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx)); cx.assert_editor_state(indoc! {" «oneˇ» «twoˇ» three @@ -2785,14 +2862,14 @@ async fn test_indent_outdent(cx: &mut gpui::TestAppContext) { t«hree ˇ» four "}); - cx.update_editor(|e, cx| e.tab(&Tab, cx)); + cx.update_editor(|e, window, cx| e.tab(&Tab, window, cx)); cx.assert_editor_state(indoc! {" one two t«hree ˇ» four "}); - cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx)); + cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx)); cx.assert_editor_state(indoc! {" one two t«hree @@ -2805,7 +2882,7 @@ async fn test_indent_outdent(cx: &mut gpui::TestAppContext) { ˇthree four "}); - cx.update_editor(|e, cx| e.tab(&Tab, cx)); + cx.update_editor(|e, window, cx| e.tab(&Tab, window, cx)); cx.assert_editor_state(indoc! {" one two ˇthree @@ -2817,7 +2894,7 @@ async fn test_indent_outdent(cx: &mut gpui::TestAppContext) { ˇ three four "}); - cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx)); + cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx)); cx.assert_editor_state(indoc! {" one two ˇthree @@ -2839,25 +2916,25 @@ async fn test_indent_outdent_with_hard_tabs(cx: &mut gpui::TestAppContext) { three four "}); - cx.update_editor(|e, cx| e.tab(&Tab, cx)); + cx.update_editor(|e, window, cx| e.tab(&Tab, window, cx)); cx.assert_editor_state(indoc! {" \t«oneˇ» «twoˇ» three four "}); - cx.update_editor(|e, cx| e.tab(&Tab, cx)); + cx.update_editor(|e, window, cx| e.tab(&Tab, window, cx)); cx.assert_editor_state(indoc! {" \t\t«oneˇ» «twoˇ» three four "}); - cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx)); + cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx)); cx.assert_editor_state(indoc! {" \t«oneˇ» «twoˇ» three four "}); - cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx)); + cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx)); cx.assert_editor_state(indoc! {" «oneˇ» «twoˇ» three @@ -2870,25 +2947,25 @@ async fn test_indent_outdent_with_hard_tabs(cx: &mut gpui::TestAppContext) { t«hree ˇ»four "}); - cx.update_editor(|e, cx| e.tab(&Tab, cx)); + cx.update_editor(|e, window, cx| e.tab(&Tab, window, cx)); cx.assert_editor_state(indoc! {" one two \tt«hree ˇ»four "}); - cx.update_editor(|e, cx| e.tab(&Tab, cx)); + cx.update_editor(|e, window, cx| e.tab(&Tab, window, cx)); cx.assert_editor_state(indoc! {" one two \t\tt«hree ˇ»four "}); - cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx)); + cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx)); cx.assert_editor_state(indoc! {" one two \tt«hree ˇ»four "}); - cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx)); + cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx)); cx.assert_editor_state(indoc! {" one two t«hree @@ -2901,19 +2978,19 @@ async fn test_indent_outdent_with_hard_tabs(cx: &mut gpui::TestAppContext) { ˇthree four "}); - cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx)); + cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx)); cx.assert_editor_state(indoc! {" one two ˇthree four "}); - cx.update_editor(|e, cx| e.tab(&Tab, cx)); + cx.update_editor(|e, window, cx| e.tab(&Tab, window, cx)); cx.assert_editor_state(indoc! {" one two \tˇthree four "}); - cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx)); + cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx)); cx.assert_editor_state(indoc! {" one two ˇthree @@ -2958,11 +3035,10 @@ fn test_indent_outdent_with_excerpts(cx: &mut TestAppContext) { )); let toml_buffer = - cx.new_model(|cx| Buffer::local("a = 1\nb = 2\n", cx).with_language(toml_language, cx)); - let rust_buffer = cx.new_model(|cx| { - Buffer::local("const c: usize = 3;\n", cx).with_language(rust_language, cx) - }); - let multibuffer = cx.new_model(|cx| { + cx.new(|cx| Buffer::local("a = 1\nb = 2\n", cx).with_language(toml_language, cx)); + let rust_buffer = + cx.new(|cx| Buffer::local("const c: usize = 3;\n", cx).with_language(rust_language, cx)); + let multibuffer = cx.new(|cx| { let mut multibuffer = MultiBuffer::new(ReadWrite); multibuffer.push_excerpts( toml_buffer.clone(), @@ -2983,8 +3059,8 @@ fn test_indent_outdent_with_excerpts(cx: &mut TestAppContext) { multibuffer }); - cx.add_window(|cx| { - let mut editor = build_editor(multibuffer, cx); + cx.add_window(|window, cx| { + let mut editor = build_editor(multibuffer, window, cx); assert_eq!( editor.text(cx), @@ -3004,10 +3080,11 @@ fn test_indent_outdent_with_excerpts(cx: &mut TestAppContext) { «const c:ˇ» usize = 3; "}, + window, cx, ); - editor.tab(&Tab, cx); + editor.tab(&Tab, window, cx); assert_text_with_selections( &mut editor, indoc! {" @@ -3018,7 +3095,7 @@ fn test_indent_outdent_with_excerpts(cx: &mut TestAppContext) { "}, cx, ); - editor.tab_prev(&TabPrev, cx); + editor.tab_prev(&TabPrev, window, cx); assert_text_with_selections( &mut editor, indoc! {" @@ -3047,7 +3124,7 @@ async fn test_backspace(cx: &mut gpui::TestAppContext) { seven «ˇeight nine »ten "}); - cx.update_editor(|e, cx| e.backspace(&Backspace, cx)); + cx.update_editor(|e, window, cx| e.backspace(&Backspace, window, cx)); cx.assert_editor_state(indoc! {" oˇe two three fouˇ five six @@ -3062,7 +3139,7 @@ async fn test_backspace(cx: &mut gpui::TestAppContext) { ˇ ˇ ˇ three ˇ ˇ four "}); - cx.update_editor(|e, cx| e.backspace(&Backspace, cx)); + cx.update_editor(|e, window, cx| e.backspace(&Backspace, window, cx)); cx.assert_editor_state(indoc! {" zero ˇone @@ -3071,13 +3148,13 @@ async fn test_backspace(cx: &mut gpui::TestAppContext) { "}); // Test backspace with line_mode set to true - cx.update_editor(|e, _| e.selections.line_mode = true); + cx.update_editor(|e, _, _| e.selections.line_mode = true); cx.set_state(indoc! {" The ˇquick ˇbrown fox jumps over the lazy dog ˇThe qu«ick bˇ»rown"}); - cx.update_editor(|e, cx| e.backspace(&Backspace, cx)); + cx.update_editor(|e, window, cx| e.backspace(&Backspace, window, cx)); cx.assert_editor_state(indoc! {" ˇfox jumps over the lazy dogˇ"}); @@ -3094,7 +3171,7 @@ async fn test_delete(cx: &mut gpui::TestAppContext) { seven «ˇeight nine »ten "}); - cx.update_editor(|e, cx| e.delete(&Delete, cx)); + cx.update_editor(|e, window, cx| e.delete(&Delete, window, cx)); cx.assert_editor_state(indoc! {" onˇ two three fouˇ five six @@ -3102,13 +3179,13 @@ async fn test_delete(cx: &mut gpui::TestAppContext) { "}); // Test backspace with line_mode set to true - cx.update_editor(|e, _| e.selections.line_mode = true); + cx.update_editor(|e, _, _| e.selections.line_mode = true); cx.set_state(indoc! {" The ˇquick ˇbrown fox «ˇjum»ps over the lazy dog ˇThe qu«ick bˇ»rown"}); - cx.update_editor(|e, cx| e.backspace(&Backspace, cx)); + cx.update_editor(|e, window, cx| e.backspace(&Backspace, window, cx)); cx.assert_editor_state("ˇthe lazy dogˇ"); } @@ -3116,22 +3193,22 @@ async fn test_delete(cx: &mut gpui::TestAppContext) { fn test_delete_line(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1), DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 1), DisplayPoint::new(DisplayRow(3), 0)..DisplayPoint::new(DisplayRow(3), 0), ]) }); - view.delete_line(&DeleteLine, cx); - assert_eq!(view.display_text(cx), "ghi"); + editor.delete_line(&DeleteLine, window, cx); + assert_eq!(editor.display_text(cx), "ghi"); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), vec![ DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0), DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1) @@ -3139,20 +3216,20 @@ fn test_delete_line(cx: &mut TestAppContext) { ); }); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(2), 0)..DisplayPoint::new(DisplayRow(0), 1) ]) }); - view.delete_line(&DeleteLine, cx); - assert_eq!(view.display_text(cx), "ghi\n"); + editor.delete_line(&DeleteLine, window, cx); + assert_eq!(editor.display_text(cx), "ghi\n"); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), vec![DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1)] ); }); @@ -3162,9 +3239,9 @@ fn test_delete_line(cx: &mut TestAppContext) { fn test_join_lines_with_single_selection(cx: &mut TestAppContext) { init_test(cx, |_| {}); - cx.add_window(|cx| { + cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("aaa\nbbb\nccc\nddd\n\n", cx); - let mut editor = build_editor(buffer.clone(), cx); + let mut editor = build_editor(buffer.clone(), window, cx); let buffer = buffer.read(cx).as_singleton().unwrap(); assert_eq!( @@ -3173,7 +3250,7 @@ fn test_join_lines_with_single_selection(cx: &mut TestAppContext) { ); // When on single line, replace newline at end by space - editor.join_lines(&JoinLines, cx); + editor.join_lines(&JoinLines, window, cx); assert_eq!(buffer.read(cx).text(), "aaa bbb\nccc\nddd\n\n"); assert_eq!( editor.selections.ranges::(cx), @@ -3181,10 +3258,10 @@ fn test_join_lines_with_single_selection(cx: &mut TestAppContext) { ); // When multiple lines are selected, remove newlines that are spanned by the selection - editor.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select_ranges([Point::new(0, 5)..Point::new(2, 2)]) }); - editor.join_lines(&JoinLines, cx); + editor.join_lines(&JoinLines, window, cx); assert_eq!(buffer.read(cx).text(), "aaa bbb ccc ddd\n\n"); assert_eq!( editor.selections.ranges::(cx), @@ -3192,7 +3269,7 @@ fn test_join_lines_with_single_selection(cx: &mut TestAppContext) { ); // Undo should be transactional - editor.undo(&Undo, cx); + editor.undo(&Undo, window, cx); assert_eq!(buffer.read(cx).text(), "aaa bbb\nccc\nddd\n\n"); assert_eq!( editor.selections.ranges::(cx), @@ -3200,10 +3277,10 @@ fn test_join_lines_with_single_selection(cx: &mut TestAppContext) { ); // When joining an empty line don't insert a space - editor.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select_ranges([Point::new(2, 1)..Point::new(2, 2)]) }); - editor.join_lines(&JoinLines, cx); + editor.join_lines(&JoinLines, window, cx); assert_eq!(buffer.read(cx).text(), "aaa bbb\nccc\nddd\n"); assert_eq!( editor.selections.ranges::(cx), @@ -3211,7 +3288,7 @@ fn test_join_lines_with_single_selection(cx: &mut TestAppContext) { ); // We can remove trailing newlines - editor.join_lines(&JoinLines, cx); + editor.join_lines(&JoinLines, window, cx); assert_eq!(buffer.read(cx).text(), "aaa bbb\nccc\nddd"); assert_eq!( editor.selections.ranges::(cx), @@ -3219,7 +3296,7 @@ fn test_join_lines_with_single_selection(cx: &mut TestAppContext) { ); // We don't blow up on the last line - editor.join_lines(&JoinLines, cx); + editor.join_lines(&JoinLines, window, cx); assert_eq!(buffer.read(cx).text(), "aaa bbb\nccc\nddd"); assert_eq!( editor.selections.ranges::(cx), @@ -3240,18 +3317,18 @@ fn test_join_lines_with_single_selection(cx: &mut TestAppContext) { // We remove any leading spaces assert_eq!(buffer.read(cx).text(), "aaa bbb\n c\n \n\td"); - editor.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select_ranges([Point::new(0, 1)..Point::new(0, 1)]) }); - editor.join_lines(&JoinLines, cx); + editor.join_lines(&JoinLines, window, cx); assert_eq!(buffer.read(cx).text(), "aaa bbb c\n \n\td"); // We don't insert a space for a line containing only spaces - editor.join_lines(&JoinLines, cx); + editor.join_lines(&JoinLines, window, cx); assert_eq!(buffer.read(cx).text(), "aaa bbb c\n\td"); // We ignore any leading tabs - editor.join_lines(&JoinLines, cx); + editor.join_lines(&JoinLines, window, cx); assert_eq!(buffer.read(cx).text(), "aaa bbb c d"); editor @@ -3262,12 +3339,12 @@ fn test_join_lines_with_single_selection(cx: &mut TestAppContext) { fn test_join_lines_with_multi_selection(cx: &mut TestAppContext) { init_test(cx, |_| {}); - cx.add_window(|cx| { + cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("aaa\nbbb\nccc\nddd\n\n", cx); - let mut editor = build_editor(buffer.clone(), cx); + let mut editor = build_editor(buffer.clone(), window, cx); let buffer = buffer.read(cx).as_singleton().unwrap(); - editor.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select_ranges([ Point::new(0, 2)..Point::new(1, 1), Point::new(1, 2)..Point::new(1, 2), @@ -3275,7 +3352,7 @@ fn test_join_lines_with_multi_selection(cx: &mut TestAppContext) { ]) }); - editor.join_lines(&JoinLines, cx); + editor.join_lines(&JoinLines, window, cx); assert_eq!(buffer.read(cx).text(), "aaa bbb ccc\nddd\n"); assert_eq!( @@ -3320,8 +3397,8 @@ async fn test_join_lines_with_git_diff_base( executor.run_until_parked(); // Join lines - cx.update_editor(|editor, cx| { - editor.join_lines(&JoinLines, cx); + cx.update_editor(|editor, window, cx| { + editor.join_lines(&JoinLines, window, cx); }); executor.run_until_parked(); @@ -3334,8 +3411,8 @@ async fn test_join_lines_with_git_diff_base( .unindent(), ); // Join again - cx.update_editor(|editor, cx| { - editor.join_lines(&JoinLines, cx); + cx.update_editor(|editor, window, cx| { + editor.join_lines(&JoinLines, window, cx); }); executor.run_until_parked(); @@ -3359,8 +3436,8 @@ async fn test_custom_newlines_cause_no_false_positive_diffs( cx.set_diff_base("Line 0\r\nLine 1\r\nLine 2\r\nLine 3"); executor.run_until_parked(); - cx.update_editor(|editor, cx| { - let snapshot = editor.snapshot(cx); + cx.update_editor(|editor, window, cx| { + let snapshot = editor.snapshot(window, cx); assert_eq!( snapshot .buffer_snapshot @@ -3387,7 +3464,9 @@ async fn test_manipulate_lines_with_single_selection(cx: &mut TestAppContext) { Y Xˇ» "}); - cx.update_editor(|e, cx| e.sort_lines_case_insensitive(&SortLinesCaseInsensitive, cx)); + cx.update_editor(|e, window, cx| { + e.sort_lines_case_insensitive(&SortLinesCaseInsensitive, window, cx) + }); cx.assert_editor_state(indoc! {" «x X @@ -3405,7 +3484,7 @@ async fn test_manipulate_lines_with_single_selection(cx: &mut TestAppContext) { 2 1ˇ» "}); - cx.update_editor(|e, cx| e.reverse_lines(&ReverseLines, cx)); + cx.update_editor(|e, window, cx| e.reverse_lines(&ReverseLines, window, cx)); cx.assert_editor_state(indoc! {" «1 2 @@ -3426,7 +3505,9 @@ async fn test_manipulate_lines_with_single_selection(cx: &mut TestAppContext) { bb a "}); - cx.update_editor(|e, cx| e.sort_lines_case_sensitive(&SortLinesCaseSensitive, cx)); + cx.update_editor(|e, window, cx| { + e.sort_lines_case_sensitive(&SortLinesCaseSensitive, window, cx) + }); cx.assert_editor_state(indoc! {" «ddddˇ» ccc @@ -3443,7 +3524,9 @@ async fn test_manipulate_lines_with_single_selection(cx: &mut TestAppContext) { bb aaaaaˇ» "}); - cx.update_editor(|e, cx| e.sort_lines_case_sensitive(&SortLinesCaseSensitive, cx)); + cx.update_editor(|e, window, cx| { + e.sort_lines_case_sensitive(&SortLinesCaseSensitive, window, cx) + }); cx.assert_editor_state(indoc! {" «aaaaa bb @@ -3461,7 +3544,9 @@ async fn test_manipulate_lines_with_single_selection(cx: &mut TestAppContext) { ˇ» "}); - cx.update_editor(|e, cx| e.sort_lines_case_sensitive(&SortLinesCaseSensitive, cx)); + cx.update_editor(|e, window, cx| { + e.sort_lines_case_sensitive(&SortLinesCaseSensitive, window, cx) + }); cx.assert_editor_state(indoc! {" « @@ -3477,7 +3562,9 @@ async fn test_manipulate_lines_with_single_selection(cx: &mut TestAppContext) { aa«a bbˇ»b "}); - cx.update_editor(|e, cx| e.manipulate_lines(cx, |lines| lines.push("added_line"))); + cx.update_editor(|e, window, cx| { + e.manipulate_lines(window, cx, |lines| lines.push("added_line")) + }); cx.assert_editor_state(indoc! {" «aaa bbb @@ -3489,8 +3576,8 @@ async fn test_manipulate_lines_with_single_selection(cx: &mut TestAppContext) { aa«a bbbˇ» "}); - cx.update_editor(|e, cx| { - e.manipulate_lines(cx, |lines| { + cx.update_editor(|e, window, cx| { + e.manipulate_lines(window, cx, |lines| { lines.pop(); }) }); @@ -3503,8 +3590,8 @@ async fn test_manipulate_lines_with_single_selection(cx: &mut TestAppContext) { aa«a bbbˇ» "}); - cx.update_editor(|e, cx| { - e.manipulate_lines(cx, |lines| { + cx.update_editor(|e, window, cx| { + e.manipulate_lines(window, cx, |lines| { lines.drain(..); }) }); @@ -3526,7 +3613,9 @@ async fn test_unique_lines_multi_selection(cx: &mut TestAppContext) { bb aaaˇ»aa "}); - cx.update_editor(|e, cx| e.unique_lines_case_sensitive(&UniqueLinesCaseSensitive, cx)); + cx.update_editor(|e, window, cx| { + e.unique_lines_case_sensitive(&UniqueLinesCaseSensitive, window, cx) + }); cx.assert_editor_state(indoc! {" «Aaaaa ccc @@ -3540,7 +3629,9 @@ async fn test_unique_lines_multi_selection(cx: &mut TestAppContext) { bb aaaˇ»aa "}); - cx.update_editor(|e, cx| e.unique_lines_case_insensitive(&UniqueLinesCaseInsensitive, cx)); + cx.update_editor(|e, window, cx| { + e.unique_lines_case_insensitive(&UniqueLinesCaseInsensitive, window, cx) + }); cx.assert_editor_state(indoc! {" «Aaaaa ccc @@ -3556,7 +3647,9 @@ async fn test_unique_lines_multi_selection(cx: &mut TestAppContext) { aaa«aaˇ» "}); - cx.update_editor(|e, cx| e.unique_lines_case_sensitive(&UniqueLinesCaseSensitive, cx)); + cx.update_editor(|e, window, cx| { + e.unique_lines_case_sensitive(&UniqueLinesCaseSensitive, window, cx) + }); cx.assert_editor_state(indoc! {" «aaaaa bbˇ» @@ -3576,7 +3669,9 @@ async fn test_unique_lines_single_selection(cx: &mut TestAppContext) { aAa Aaaˇ» "}); - cx.update_editor(|e, cx| e.unique_lines_case_sensitive(&UniqueLinesCaseSensitive, cx)); + cx.update_editor(|e, window, cx| { + e.unique_lines_case_sensitive(&UniqueLinesCaseSensitive, window, cx) + }); cx.assert_editor_state(indoc! {" «Aaa aAaˇ» @@ -3587,7 +3682,9 @@ async fn test_unique_lines_single_selection(cx: &mut TestAppContext) { aAa aaAˇ» "}); - cx.update_editor(|e, cx| e.unique_lines_case_insensitive(&UniqueLinesCaseInsensitive, cx)); + cx.update_editor(|e, window, cx| { + e.unique_lines_case_insensitive(&UniqueLinesCaseInsensitive, window, cx) + }); cx.assert_editor_state(indoc! {" «Aaaˇ» "}); @@ -3606,7 +3703,9 @@ async fn test_manipulate_lines_with_multi_selection(cx: &mut TestAppContext) { bb aaaˇ»aa "}); - cx.update_editor(|e, cx| e.sort_lines_case_sensitive(&SortLinesCaseSensitive, cx)); + cx.update_editor(|e, window, cx| { + e.sort_lines_case_sensitive(&SortLinesCaseSensitive, window, cx) + }); cx.assert_editor_state(indoc! {" «aaaaa bb @@ -3627,7 +3726,9 @@ async fn test_manipulate_lines_with_multi_selection(cx: &mut TestAppContext) { bb aaaˇ»aa "}); - cx.update_editor(|e, cx| e.sort_lines_case_sensitive(&SortLinesCaseSensitive, cx)); + cx.update_editor(|e, window, cx| { + e.sort_lines_case_sensitive(&SortLinesCaseSensitive, window, cx) + }); cx.assert_editor_state(indoc! {" «1 2 @@ -3649,7 +3750,9 @@ async fn test_manipulate_lines_with_multi_selection(cx: &mut TestAppContext) { bb«bb aaaˇ»aa "}); - cx.update_editor(|e, cx| e.manipulate_lines(cx, |lines| lines.push("added line"))); + cx.update_editor(|e, window, cx| { + e.manipulate_lines(window, cx, |lines| lines.push("added line")) + }); cx.assert_editor_state(indoc! {" «2 1 @@ -3668,8 +3771,8 @@ async fn test_manipulate_lines_with_multi_selection(cx: &mut TestAppContext) { bb«bb aaaˇ»aa "}); - cx.update_editor(|e, cx| { - e.manipulate_lines(cx, |lines| { + cx.update_editor(|e, window, cx| { + e.manipulate_lines(window, cx, |lines| { lines.pop(); }) }); @@ -3690,7 +3793,7 @@ async fn test_manipulate_text(cx: &mut TestAppContext) { cx.set_state(indoc! {" «hello worldˇ» "}); - cx.update_editor(|e, cx| e.convert_to_upper_case(&ConvertToUpperCase, cx)); + cx.update_editor(|e, window, cx| e.convert_to_upper_case(&ConvertToUpperCase, window, cx)); cx.assert_editor_state(indoc! {" «HELLO WORLDˇ» "}); @@ -3699,7 +3802,7 @@ async fn test_manipulate_text(cx: &mut TestAppContext) { cx.set_state(indoc! {" «HELLO WORLDˇ» "}); - cx.update_editor(|e, cx| e.convert_to_lower_case(&ConvertToLowerCase, cx)); + cx.update_editor(|e, window, cx| e.convert_to_lower_case(&ConvertToLowerCase, window, cx)); cx.assert_editor_state(indoc! {" «hello worldˇ» "}); @@ -3710,7 +3813,7 @@ async fn test_manipulate_text(cx: &mut TestAppContext) { fox jumps over the lazy dogˇ» "}); - cx.update_editor(|e, cx| e.convert_to_title_case(&ConvertToTitleCase, cx)); + cx.update_editor(|e, window, cx| e.convert_to_title_case(&ConvertToTitleCase, window, cx)); cx.assert_editor_state(indoc! {" «The Quick Brown Fox Jumps Over @@ -3723,7 +3826,9 @@ async fn test_manipulate_text(cx: &mut TestAppContext) { fox jumps over the lazy dogˇ» "}); - cx.update_editor(|e, cx| e.convert_to_upper_camel_case(&ConvertToUpperCamelCase, cx)); + cx.update_editor(|e, window, cx| { + e.convert_to_upper_camel_case(&ConvertToUpperCamelCase, window, cx) + }); cx.assert_editor_state(indoc! {" «TheQuickBrown FoxJumpsOver @@ -3737,7 +3842,7 @@ async fn test_manipulate_text(cx: &mut TestAppContext) { cx.set_state(indoc! {" ˇhello big beauˇtiful worldˇ "}); - cx.update_editor(|e, cx| e.convert_to_upper_case(&ConvertToUpperCase, cx)); + cx.update_editor(|e, window, cx| e.convert_to_upper_case(&ConvertToUpperCase, window, cx)); cx.assert_editor_state(indoc! {" «HELLOˇ» big «BEAUTIFULˇ» «WORLDˇ» "}); @@ -3748,7 +3853,7 @@ async fn test_manipulate_text(cx: &mut TestAppContext) { foxˇ» jumps «overˇ» the «lazyˇ» dog "}); - cx.update_editor(|e, cx| e.convert_to_upper_case(&ConvertToUpperCase, cx)); + cx.update_editor(|e, window, cx| e.convert_to_upper_case(&ConvertToUpperCase, window, cx)); cx.assert_editor_state(indoc! {" «THEˇ» quick «BROWN FOXˇ» jumps «OVERˇ» @@ -3759,7 +3864,7 @@ async fn test_manipulate_text(cx: &mut TestAppContext) { cx.set_state(indoc! {" «tschüߡ» "}); - cx.update_editor(|e, cx| e.convert_to_upper_case(&ConvertToUpperCase, cx)); + cx.update_editor(|e, window, cx| e.convert_to_upper_case(&ConvertToUpperCase, window, cx)); cx.assert_editor_state(indoc! {" «TSCHÜSSˇ» "}); @@ -3768,7 +3873,9 @@ async fn test_manipulate_text(cx: &mut TestAppContext) { cx.set_state(indoc! {" aaa_bbbˇ "}); - cx.update_editor(|e, cx| e.convert_to_lower_camel_case(&ConvertToLowerCamelCase, cx)); + cx.update_editor(|e, window, cx| { + e.convert_to_lower_camel_case(&ConvertToLowerCamelCase, window, cx) + }); cx.assert_editor_state(indoc! {" «aaaBbbˇ» "}); @@ -3778,7 +3885,9 @@ async fn test_manipulate_text(cx: &mut TestAppContext) { cx.set_state(indoc! {" aaa_bˇbb bbˇb_ccc ˇccc_ddd "}); - cx.update_editor(|e, cx| e.convert_to_lower_camel_case(&ConvertToLowerCamelCase, cx)); + cx.update_editor(|e, window, cx| { + e.convert_to_lower_camel_case(&ConvertToLowerCamelCase, window, cx) + }); cx.assert_editor_state(indoc! {" «aaaBbbˇ» «bbbCccˇ» «cccDddˇ» "}); @@ -3786,7 +3895,9 @@ async fn test_manipulate_text(cx: &mut TestAppContext) { cx.set_state(indoc! {" «hElLo, WoRld!ˇ» "}); - cx.update_editor(|e, cx| e.convert_to_opposite_case(&ConvertToOppositeCase, cx)); + cx.update_editor(|e, window, cx| { + e.convert_to_opposite_case(&ConvertToOppositeCase, window, cx) + }); cx.assert_editor_state(indoc! {" «HeLlO, wOrLD!ˇ» "}); @@ -3796,12 +3907,12 @@ async fn test_manipulate_text(cx: &mut TestAppContext) { fn test_duplicate_line(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1), DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), @@ -3809,10 +3920,10 @@ fn test_duplicate_line(cx: &mut TestAppContext) { DisplayPoint::new(DisplayRow(3), 0)..DisplayPoint::new(DisplayRow(3), 0), ]) }); - view.duplicate_line_down(&DuplicateLineDown, cx); - assert_eq!(view.display_text(cx), "abc\nabc\ndef\ndef\nghi\n\n"); + editor.duplicate_line_down(&DuplicateLineDown, window, cx); + assert_eq!(editor.display_text(cx), "abc\nabc\ndef\ndef\nghi\n\n"); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), vec![ DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 1), DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(1), 2), @@ -3822,21 +3933,21 @@ fn test_duplicate_line(cx: &mut TestAppContext) { ); }); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(1), 1), DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(2), 1), ]) }); - view.duplicate_line_down(&DuplicateLineDown, cx); - assert_eq!(view.display_text(cx), "abc\ndef\nghi\nabc\ndef\nghi\n"); + editor.duplicate_line_down(&DuplicateLineDown, window, cx); + assert_eq!(editor.display_text(cx), "abc\ndef\nghi\nabc\ndef\nghi\n"); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), vec![ DisplayPoint::new(DisplayRow(3), 1)..DisplayPoint::new(DisplayRow(4), 1), DisplayPoint::new(DisplayRow(4), 2)..DisplayPoint::new(DisplayRow(5), 1), @@ -3846,12 +3957,12 @@ fn test_duplicate_line(cx: &mut TestAppContext) { // With `move_upwards` the selections stay in place, except for // the lines inserted above them - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1), DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), @@ -3859,10 +3970,10 @@ fn test_duplicate_line(cx: &mut TestAppContext) { DisplayPoint::new(DisplayRow(3), 0)..DisplayPoint::new(DisplayRow(3), 0), ]) }); - view.duplicate_line_up(&DuplicateLineUp, cx); - assert_eq!(view.display_text(cx), "abc\nabc\ndef\ndef\nghi\n\n"); + editor.duplicate_line_up(&DuplicateLineUp, window, cx); + assert_eq!(editor.display_text(cx), "abc\nabc\ndef\ndef\nghi\n\n"); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), vec![ DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1), DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), @@ -3872,21 +3983,21 @@ fn test_duplicate_line(cx: &mut TestAppContext) { ); }); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(1), 1), DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(2), 1), ]) }); - view.duplicate_line_up(&DuplicateLineUp, cx); - assert_eq!(view.display_text(cx), "abc\ndef\nghi\nabc\ndef\nghi\n"); + editor.duplicate_line_up(&DuplicateLineUp, window, cx); + assert_eq!(editor.display_text(cx), "abc\ndef\nghi\nabc\ndef\nghi\n"); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), vec![ DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(1), 1), DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(2), 1), @@ -3894,21 +4005,21 @@ fn test_duplicate_line(cx: &mut TestAppContext) { ); }); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(1), 1), DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(2), 1), ]) }); - view.duplicate_selection(&DuplicateSelection, cx); - assert_eq!(view.display_text(cx), "abc\ndbc\ndef\ngf\nghi\n"); + editor.duplicate_selection(&DuplicateSelection, window, cx); + assert_eq!(editor.display_text(cx), "abc\ndbc\ndef\ngf\nghi\n"); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), vec![ DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(1), 1), DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(3), 1), @@ -3921,21 +4032,22 @@ fn test_duplicate_line(cx: &mut TestAppContext) { fn test_move_line_up_down(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.fold_creases( + _ = editor.update(cx, |editor, window, cx| { + editor.fold_creases( vec![ Crease::simple(Point::new(0, 2)..Point::new(1, 2), FoldPlaceholder::test()), Crease::simple(Point::new(2, 3)..Point::new(4, 1), FoldPlaceholder::test()), Crease::simple(Point::new(7, 0)..Point::new(8, 4), FoldPlaceholder::test()), ], true, + window, cx, ); - view.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1), DisplayPoint::new(DisplayRow(3), 1)..DisplayPoint::new(DisplayRow(3), 1), @@ -3944,17 +4056,17 @@ fn test_move_line_up_down(cx: &mut TestAppContext) { ]) }); assert_eq!( - view.display_text(cx), + editor.display_text(cx), "aa⋯bbb\nccc⋯eeee\nfffff\nggggg\n⋯i\njjjjj" ); - view.move_line_up(&MoveLineUp, cx); + editor.move_line_up(&MoveLineUp, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), "aa⋯bbb\nccc⋯eeee\nggggg\n⋯i\njjjjj\nfffff" ); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), vec![ DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1), DisplayPoint::new(DisplayRow(2), 1)..DisplayPoint::new(DisplayRow(2), 1), @@ -3964,14 +4076,14 @@ fn test_move_line_up_down(cx: &mut TestAppContext) { ); }); - _ = view.update(cx, |view, cx| { - view.move_line_down(&MoveLineDown, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.move_line_down(&MoveLineDown, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), "ccc⋯eeee\naa⋯bbb\nfffff\nggggg\n⋯i\njjjjj" ); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), vec![ DisplayPoint::new(DisplayRow(1), 1)..DisplayPoint::new(DisplayRow(1), 1), DisplayPoint::new(DisplayRow(3), 1)..DisplayPoint::new(DisplayRow(3), 1), @@ -3981,14 +4093,14 @@ fn test_move_line_up_down(cx: &mut TestAppContext) { ); }); - _ = view.update(cx, |view, cx| { - view.move_line_down(&MoveLineDown, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.move_line_down(&MoveLineDown, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), "ccc⋯eeee\nfffff\naa⋯bbb\nggggg\n⋯i\njjjjj" ); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), vec![ DisplayPoint::new(DisplayRow(2), 1)..DisplayPoint::new(DisplayRow(2), 1), DisplayPoint::new(DisplayRow(3), 1)..DisplayPoint::new(DisplayRow(3), 1), @@ -3998,14 +4110,14 @@ fn test_move_line_up_down(cx: &mut TestAppContext) { ); }); - _ = view.update(cx, |view, cx| { - view.move_line_up(&MoveLineUp, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.move_line_up(&MoveLineUp, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), "ccc⋯eeee\naa⋯bbb\nggggg\n⋯i\njjjjj\nfffff" ); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), vec![ DisplayPoint::new(DisplayRow(1), 1)..DisplayPoint::new(DisplayRow(1), 1), DisplayPoint::new(DisplayRow(2), 1)..DisplayPoint::new(DisplayRow(2), 1), @@ -4020,11 +4132,11 @@ fn test_move_line_up_down(cx: &mut TestAppContext) { fn test_move_line_up_down_with_blocks(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let editor = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = editor.update(cx, |editor, cx| { + _ = editor.update(cx, |editor, window, cx| { let snapshot = editor.buffer.read(cx).snapshot(cx); editor.insert_blocks( [BlockProperties { @@ -4037,10 +4149,10 @@ fn test_move_line_up_down_with_blocks(cx: &mut TestAppContext) { Some(Autoscroll::fit()), cx, ); - editor.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select_ranges([Point::new(2, 0)..Point::new(2, 0)]) }); - editor.move_line_down(&MoveLineDown, cx); + editor.move_line_down(&MoveLineDown, window, cx); }); } @@ -4062,8 +4174,8 @@ async fn test_selections_and_replace_blocks(cx: &mut TestAppContext) { ); // Create a four-line block that replaces three lines of text. - cx.update_editor(|editor, cx| { - let snapshot = editor.snapshot(cx); + cx.update_editor(|editor, window, cx| { + let snapshot = editor.snapshot(window, cx); let snapshot = &snapshot.buffer_snapshot; let placement = BlockPlacement::Replace( snapshot.anchor_after(Point::new(1, 0))..=snapshot.anchor_after(Point::new(3, 0)), @@ -4082,8 +4194,8 @@ async fn test_selections_and_replace_blocks(cx: &mut TestAppContext) { }); // Move down so that the cursor touches the block. - cx.update_editor(|editor, cx| { - editor.move_down(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.move_down(&Default::default(), window, cx); }); cx.assert_editor_state( &" @@ -4098,8 +4210,8 @@ async fn test_selections_and_replace_blocks(cx: &mut TestAppContext) { ); // Move down past the block. - cx.update_editor(|editor, cx| { - editor.move_down(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.move_down(&Default::default(), window, cx); }); cx.assert_editor_state( &" @@ -4118,89 +4230,89 @@ async fn test_selections_and_replace_blocks(cx: &mut TestAppContext) { fn test_transpose(cx: &mut TestAppContext) { init_test(cx, |_| {}); - _ = cx.add_window(|cx| { - let mut editor = build_editor(MultiBuffer::build_simple("abc", cx), cx); - editor.set_style(EditorStyle::default(), cx); - editor.change_selections(None, cx, |s| s.select_ranges([1..1])); - editor.transpose(&Default::default(), cx); + _ = cx.add_window(|window, cx| { + let mut editor = build_editor(MultiBuffer::build_simple("abc", cx), window, cx); + editor.set_style(EditorStyle::default(), window, cx); + editor.change_selections(None, window, cx, |s| s.select_ranges([1..1])); + editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "bac"); assert_eq!(editor.selections.ranges(cx), [2..2]); - editor.transpose(&Default::default(), cx); + editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "bca"); assert_eq!(editor.selections.ranges(cx), [3..3]); - editor.transpose(&Default::default(), cx); + editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "bac"); assert_eq!(editor.selections.ranges(cx), [3..3]); editor }); - _ = cx.add_window(|cx| { - let mut editor = build_editor(MultiBuffer::build_simple("abc\nde", cx), cx); - editor.set_style(EditorStyle::default(), cx); - editor.change_selections(None, cx, |s| s.select_ranges([3..3])); - editor.transpose(&Default::default(), cx); + _ = cx.add_window(|window, cx| { + let mut editor = build_editor(MultiBuffer::build_simple("abc\nde", cx), window, cx); + editor.set_style(EditorStyle::default(), window, cx); + editor.change_selections(None, window, cx, |s| s.select_ranges([3..3])); + editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "acb\nde"); assert_eq!(editor.selections.ranges(cx), [3..3]); - editor.change_selections(None, cx, |s| s.select_ranges([4..4])); - editor.transpose(&Default::default(), cx); + editor.change_selections(None, window, cx, |s| s.select_ranges([4..4])); + editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "acbd\ne"); assert_eq!(editor.selections.ranges(cx), [5..5]); - editor.transpose(&Default::default(), cx); + editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "acbde\n"); assert_eq!(editor.selections.ranges(cx), [6..6]); - editor.transpose(&Default::default(), cx); + editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "acbd\ne"); assert_eq!(editor.selections.ranges(cx), [6..6]); editor }); - _ = cx.add_window(|cx| { - let mut editor = build_editor(MultiBuffer::build_simple("abc\nde", cx), cx); - editor.set_style(EditorStyle::default(), cx); - editor.change_selections(None, cx, |s| s.select_ranges([1..1, 2..2, 4..4])); - editor.transpose(&Default::default(), cx); + _ = cx.add_window(|window, cx| { + let mut editor = build_editor(MultiBuffer::build_simple("abc\nde", cx), window, cx); + editor.set_style(EditorStyle::default(), window, cx); + editor.change_selections(None, window, cx, |s| s.select_ranges([1..1, 2..2, 4..4])); + editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "bacd\ne"); assert_eq!(editor.selections.ranges(cx), [2..2, 3..3, 5..5]); - editor.transpose(&Default::default(), cx); + editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "bcade\n"); assert_eq!(editor.selections.ranges(cx), [3..3, 4..4, 6..6]); - editor.transpose(&Default::default(), cx); + editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "bcda\ne"); assert_eq!(editor.selections.ranges(cx), [4..4, 6..6]); - editor.transpose(&Default::default(), cx); + editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "bcade\n"); assert_eq!(editor.selections.ranges(cx), [4..4, 6..6]); - editor.transpose(&Default::default(), cx); + editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "bcaed\n"); assert_eq!(editor.selections.ranges(cx), [5..5, 6..6]); editor }); - _ = cx.add_window(|cx| { - let mut editor = build_editor(MultiBuffer::build_simple("🍐🏀✋", cx), cx); - editor.set_style(EditorStyle::default(), cx); - editor.change_selections(None, cx, |s| s.select_ranges([4..4])); - editor.transpose(&Default::default(), cx); + _ = cx.add_window(|window, cx| { + let mut editor = build_editor(MultiBuffer::build_simple("🍐🏀✋", cx), window, cx); + editor.set_style(EditorStyle::default(), window, cx); + editor.change_selections(None, window, cx, |s| s.select_ranges([4..4])); + editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "🏀🍐✋"); assert_eq!(editor.selections.ranges(cx), [8..8]); - editor.transpose(&Default::default(), cx); + editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "🏀✋🍐"); assert_eq!(editor.selections.ranges(cx), [11..11]); - editor.transpose(&Default::default(), cx); + editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "🏀🍐✋"); assert_eq!(editor.selections.ranges(cx), [11..11]); @@ -4490,7 +4602,7 @@ async fn test_rewrap(cx: &mut TestAppContext) { ) { cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx)); cx.set_state(unwrapped_text); - cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx)); + cx.update_editor(|e, window, cx| e.rewrap(&Rewrap, window, cx)); cx.assert_editor_state(wrapped_text); } } @@ -4502,22 +4614,22 @@ async fn test_clipboard(cx: &mut gpui::TestAppContext) { let mut cx = EditorTestContext::new(cx).await; cx.set_state("«one✅ ˇ»two «three ˇ»four «five ˇ»six "); - cx.update_editor(|e, cx| e.cut(&Cut, cx)); + cx.update_editor(|e, window, cx| e.cut(&Cut, window, cx)); cx.assert_editor_state("ˇtwo ˇfour ˇsix "); // Paste with three cursors. Each cursor pastes one slice of the clipboard text. cx.set_state("two ˇfour ˇsix ˇ"); - cx.update_editor(|e, cx| e.paste(&Paste, cx)); + cx.update_editor(|e, window, cx| e.paste(&Paste, window, cx)); cx.assert_editor_state("two one✅ ˇfour three ˇsix five ˇ"); // Paste again but with only two cursors. Since the number of cursors doesn't // match the number of slices in the clipboard, the entire clipboard text // is pasted at each cursor. cx.set_state("ˇtwo one✅ four three six five ˇ"); - cx.update_editor(|e, cx| { - e.handle_input("( ", cx); - e.paste(&Paste, cx); - e.handle_input(") ", cx); + cx.update_editor(|e, window, cx| { + e.handle_input("( ", window, cx); + e.paste(&Paste, window, cx); + e.handle_input(") ", window, cx); }); cx.assert_editor_state( &([ @@ -4535,7 +4647,7 @@ async fn test_clipboard(cx: &mut gpui::TestAppContext) { 1«2ˇ»3 4ˇ567 «8ˇ»9"}); - cx.update_editor(|e, cx| e.cut(&Cut, cx)); + cx.update_editor(|e, window, cx| e.cut(&Cut, window, cx)); cx.assert_editor_state(indoc! {" 1ˇ3 ˇ9"}); @@ -4546,7 +4658,7 @@ async fn test_clipboard(cx: &mut gpui::TestAppContext) { 1ˇ3 9ˇ «oˇ»ne"}); - cx.update_editor(|e, cx| e.paste(&Paste, cx)); + cx.update_editor(|e, window, cx| e.paste(&Paste, window, cx)); cx.assert_editor_state(indoc! {" 12ˇ3 4567 @@ -4558,7 +4670,7 @@ async fn test_clipboard(cx: &mut gpui::TestAppContext) { The quick brown fox juˇmps over the lazy dog"}); - cx.update_editor(|e, cx| e.copy(&Copy, cx)); + cx.update_editor(|e, window, cx| e.copy(&Copy, window, cx)); assert_eq!( cx.read_from_clipboard() .and_then(|item| item.text().as_deref().map(str::to_string)), @@ -4571,7 +4683,7 @@ async fn test_clipboard(cx: &mut gpui::TestAppContext) { Tˇhe quick brown «foˇ»x jumps over tˇhe lazy dog"}); - cx.update_editor(|e, cx| e.paste(&Paste, cx)); + cx.update_editor(|e, window, cx| e.paste(&Paste, window, cx)); cx.assert_editor_state(indoc! {" fox jumps over Tˇhe quick brown @@ -4602,7 +4714,7 @@ async fn test_paste_multiline(cx: &mut gpui::TestAppContext) { )ˇ» ); "}); - cx.update_editor(|e, cx| e.cut(&Cut, cx)); + cx.update_editor(|e, window, cx| e.cut(&Cut, window, cx)); cx.assert_editor_state(indoc! {" const a: B = ( c(), @@ -4611,7 +4723,7 @@ async fn test_paste_multiline(cx: &mut gpui::TestAppContext) { "}); // Paste it at the same position. - cx.update_editor(|e, cx| e.paste(&Paste, cx)); + cx.update_editor(|e, window, cx| e.paste(&Paste, window, cx)); cx.assert_editor_state(indoc! {" const a: B = ( c(), @@ -4629,7 +4741,7 @@ async fn test_paste_multiline(cx: &mut gpui::TestAppContext) { c(), ); "}); - cx.update_editor(|e, cx| e.paste(&Paste, cx)); + cx.update_editor(|e, window, cx| e.paste(&Paste, window, cx)); cx.assert_editor_state(indoc! {" d( e, @@ -4650,7 +4762,7 @@ async fn test_paste_multiline(cx: &mut gpui::TestAppContext) { ) ˇ»); "}); - cx.update_editor(|e, cx| e.cut(&Cut, cx)); + cx.update_editor(|e, window, cx| e.cut(&Cut, window, cx)); cx.assert_editor_state(indoc! {" const a: B = ( c(), @@ -4658,7 +4770,7 @@ async fn test_paste_multiline(cx: &mut gpui::TestAppContext) { "}); // Paste it at the same position. - cx.update_editor(|e, cx| e.paste(&Paste, cx)); + cx.update_editor(|e, window, cx| e.paste(&Paste, window, cx)); cx.assert_editor_state(indoc! {" const a: B = ( c(), @@ -4679,7 +4791,7 @@ async fn test_paste_multiline(cx: &mut gpui::TestAppContext) { ) ); "}); - cx.update_editor(|e, cx| e.paste(&Paste, cx)); + cx.update_editor(|e, window, cx| e.paste(&Paste, window, cx)); cx.assert_editor_state(indoc! {" const a: B = ( c(), @@ -4699,14 +4811,14 @@ async fn test_paste_multiline(cx: &mut gpui::TestAppContext) { fn test_select_all(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple("abc\nde\nfgh", cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.select_all(&SelectAll, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.select_all(&SelectAll, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), &[DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(2), 3)] ); }); @@ -4716,12 +4828,12 @@ fn test_select_all(cx: &mut TestAppContext) { fn test_select_line(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple(&sample_text(6, 5, 'a'), cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1), DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), @@ -4729,9 +4841,9 @@ fn test_select_line(cx: &mut TestAppContext) { DisplayPoint::new(DisplayRow(4), 2)..DisplayPoint::new(DisplayRow(4), 2), ]) }); - view.select_line(&SelectLine, cx); + editor.select_line(&SelectLine, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), vec![ DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(2), 0), DisplayPoint::new(DisplayRow(4), 0)..DisplayPoint::new(DisplayRow(5), 0), @@ -4739,10 +4851,10 @@ fn test_select_line(cx: &mut TestAppContext) { ); }); - _ = view.update(cx, |view, cx| { - view.select_line(&SelectLine, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.select_line(&SelectLine, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), vec![ DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(3), 0), DisplayPoint::new(DisplayRow(4), 0)..DisplayPoint::new(DisplayRow(5), 5), @@ -4750,10 +4862,10 @@ fn test_select_line(cx: &mut TestAppContext) { ); }); - _ = view.update(cx, |view, cx| { - view.select_line(&SelectLine, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.select_line(&SelectLine, window, cx); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), vec![DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(5), 5)] ); }); @@ -4763,21 +4875,22 @@ fn test_select_line(cx: &mut TestAppContext) { fn test_split_selection_into_lines(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let view = cx.add_window(|cx| { + let editor = cx.add_window(|window, cx| { let buffer = MultiBuffer::build_simple(&sample_text(9, 5, 'a'), cx); - build_editor(buffer, cx) + build_editor(buffer, window, cx) }); - _ = view.update(cx, |view, cx| { - view.fold_creases( + _ = editor.update(cx, |editor, window, cx| { + editor.fold_creases( vec![ Crease::simple(Point::new(0, 2)..Point::new(1, 2), FoldPlaceholder::test()), Crease::simple(Point::new(2, 3)..Point::new(4, 1), FoldPlaceholder::test()), Crease::simple(Point::new(7, 0)..Point::new(8, 4), FoldPlaceholder::test()), ], true, + window, cx, ); - view.change_selections(None, cx, |s| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1), DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), @@ -4785,17 +4898,20 @@ fn test_split_selection_into_lines(cx: &mut TestAppContext) { DisplayPoint::new(DisplayRow(4), 4)..DisplayPoint::new(DisplayRow(4), 4), ]) }); - assert_eq!(view.display_text(cx), "aa⋯bbb\nccc⋯eeee\nfffff\nggggg\n⋯i"); + assert_eq!( + editor.display_text(cx), + "aa⋯bbb\nccc⋯eeee\nfffff\nggggg\n⋯i" + ); }); - _ = view.update(cx, |view, cx| { - view.split_selection_into_lines(&SplitSelectionIntoLines, cx); + _ = editor.update(cx, |editor, window, cx| { + editor.split_selection_into_lines(&SplitSelectionIntoLines, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), "aaaaa\nbbbbb\nccc⋯eeee\nfffff\nggggg\n⋯i" ); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), [ DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1), DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), @@ -4805,19 +4921,19 @@ fn test_split_selection_into_lines(cx: &mut TestAppContext) { ); }); - _ = view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(5), 0)..DisplayPoint::new(DisplayRow(0), 1) ]) }); - view.split_selection_into_lines(&SplitSelectionIntoLines, cx); + editor.split_selection_into_lines(&SplitSelectionIntoLines, window, cx); assert_eq!( - view.display_text(cx), + editor.display_text(cx), "aaaaa\nbbbbb\nccccc\nddddd\neeeee\nfffff\nggggg\nhhhhh\niiiii" ); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), [ DisplayPoint::new(DisplayRow(0), 5)..DisplayPoint::new(DisplayRow(0), 5), DisplayPoint::new(DisplayRow(1), 5)..DisplayPoint::new(DisplayRow(1), 5), @@ -4848,8 +4964,8 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) { "# )); - cx.update_editor(|editor, cx| { - editor.add_selection_above(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.add_selection_above(&Default::default(), window, cx); }); cx.assert_editor_state(indoc!( @@ -4861,8 +4977,8 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) { "# )); - cx.update_editor(|editor, cx| { - editor.add_selection_above(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.add_selection_above(&Default::default(), window, cx); }); cx.assert_editor_state(indoc!( @@ -4874,8 +4990,8 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) { "# )); - cx.update_editor(|view, cx| { - view.add_selection_below(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.add_selection_below(&Default::default(), window, cx); }); cx.assert_editor_state(indoc!( @@ -4887,8 +5003,8 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) { "# )); - cx.update_editor(|view, cx| { - view.undo_selection(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.undo_selection(&Default::default(), window, cx); }); cx.assert_editor_state(indoc!( @@ -4900,8 +5016,8 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) { "# )); - cx.update_editor(|view, cx| { - view.redo_selection(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.redo_selection(&Default::default(), window, cx); }); cx.assert_editor_state(indoc!( @@ -4913,8 +5029,8 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) { "# )); - cx.update_editor(|view, cx| { - view.add_selection_below(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.add_selection_below(&Default::default(), window, cx); }); cx.assert_editor_state(indoc!( @@ -4926,8 +5042,8 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) { "# )); - cx.update_editor(|view, cx| { - view.add_selection_below(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.add_selection_below(&Default::default(), window, cx); }); cx.assert_editor_state(indoc!( @@ -4949,8 +5065,8 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) { "# )); - cx.update_editor(|view, cx| { - view.add_selection_below(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.add_selection_below(&Default::default(), window, cx); }); cx.assert_editor_state(indoc!( @@ -4962,8 +5078,8 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) { "# )); - cx.update_editor(|view, cx| { - view.add_selection_below(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.add_selection_below(&Default::default(), window, cx); }); cx.assert_editor_state(indoc!( @@ -4975,8 +5091,8 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) { "# )); - cx.update_editor(|view, cx| { - view.add_selection_above(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.add_selection_above(&Default::default(), window, cx); }); cx.assert_editor_state(indoc!( @@ -4988,8 +5104,8 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) { "# )); - cx.update_editor(|view, cx| { - view.add_selection_above(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.add_selection_above(&Default::default(), window, cx); }); cx.assert_editor_state(indoc!( @@ -5011,8 +5127,8 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) { "# )); - cx.update_editor(|view, cx| { - view.add_selection_below(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.add_selection_below(&Default::default(), window, cx); }); cx.assert_editor_state(indoc!( @@ -5024,8 +5140,8 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) { "# )); - cx.update_editor(|view, cx| { - view.add_selection_below(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.add_selection_below(&Default::default(), window, cx); }); cx.assert_editor_state(indoc!( r#"a«bcˇ» @@ -5035,8 +5151,8 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) { n«lmoˇ» "# )); - cx.update_editor(|view, cx| { - view.add_selection_above(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.add_selection_above(&Default::default(), window, cx); }); cx.assert_editor_state(indoc!( @@ -5058,8 +5174,8 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) { "# )); - cx.update_editor(|view, cx| { - view.add_selection_above(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.add_selection_above(&Default::default(), window, cx); }); cx.assert_editor_state(indoc!( @@ -5071,8 +5187,8 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) { "# )); - cx.update_editor(|view, cx| { - view.add_selection_below(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.add_selection_below(&Default::default(), window, cx); }); cx.assert_editor_state(indoc!( @@ -5092,25 +5208,25 @@ async fn test_select_next(cx: &mut gpui::TestAppContext) { let mut cx = EditorTestContext::new(cx).await; cx.set_state("abc\nˇabc abc\ndefabc\nabc"); - cx.update_editor(|e, cx| e.select_next(&SelectNext::default(), cx)) + cx.update_editor(|e, window, cx| e.select_next(&SelectNext::default(), window, cx)) .unwrap(); cx.assert_editor_state("abc\n«abcˇ» abc\ndefabc\nabc"); - cx.update_editor(|e, cx| e.select_next(&SelectNext::default(), cx)) + cx.update_editor(|e, window, cx| e.select_next(&SelectNext::default(), window, cx)) .unwrap(); cx.assert_editor_state("abc\n«abcˇ» «abcˇ»\ndefabc\nabc"); - cx.update_editor(|view, cx| view.undo_selection(&UndoSelection, cx)); + cx.update_editor(|editor, window, cx| editor.undo_selection(&UndoSelection, window, cx)); cx.assert_editor_state("abc\n«abcˇ» abc\ndefabc\nabc"); - cx.update_editor(|view, cx| view.redo_selection(&RedoSelection, cx)); + cx.update_editor(|editor, window, cx| editor.redo_selection(&RedoSelection, window, cx)); cx.assert_editor_state("abc\n«abcˇ» «abcˇ»\ndefabc\nabc"); - cx.update_editor(|e, cx| e.select_next(&SelectNext::default(), cx)) + cx.update_editor(|e, window, cx| e.select_next(&SelectNext::default(), window, cx)) .unwrap(); cx.assert_editor_state("abc\n«abcˇ» «abcˇ»\ndefabc\n«abcˇ»"); - cx.update_editor(|e, cx| e.select_next(&SelectNext::default(), cx)) + cx.update_editor(|e, window, cx| e.select_next(&SelectNext::default(), window, cx)) .unwrap(); cx.assert_editor_state("«abcˇ»\n«abcˇ» «abcˇ»\ndefabc\n«abcˇ»"); } @@ -5122,7 +5238,7 @@ async fn test_select_all_matches(cx: &mut gpui::TestAppContext) { let mut cx = EditorTestContext::new(cx).await; cx.set_state("abc\nˇabc abc\ndefabc\nabc"); - cx.update_editor(|e, cx| e.select_all_matches(&SelectAllMatches, cx)) + cx.update_editor(|e, window, cx| e.select_all_matches(&SelectAllMatches, window, cx)) .unwrap(); cx.assert_editor_state("«abcˇ»\n«abcˇ» «abcˇ»\ndefabc\n«abcˇ»"); } @@ -5140,7 +5256,7 @@ let foo = 2; let foo = ˇ2;"#, ); - cx.update_editor(|e, cx| e.select_next(&SelectNext::default(), cx)) + cx.update_editor(|e, window, cx| e.select_next(&SelectNext::default(), window, cx)) .unwrap(); cx.assert_editor_state( r#"let foo = 2; @@ -5151,7 +5267,7 @@ let foo = «2ˇ»;"#, ); // noop for multiple selections with different contents - cx.update_editor(|e, cx| e.select_next(&SelectNext::default(), cx)) + cx.update_editor(|e, window, cx| e.select_next(&SelectNext::default(), window, cx)) .unwrap(); cx.assert_editor_state( r#"let foo = 2; @@ -5201,29 +5317,29 @@ async fn test_select_previous_with_single_caret(cx: &mut gpui::TestAppContext) { let mut cx = EditorTestContext::new(cx).await; cx.set_state("abc\nˇabc abc\ndefabc\nabc"); - cx.update_editor(|e, cx| e.select_previous(&SelectPrevious::default(), cx)) + cx.update_editor(|e, window, cx| e.select_previous(&SelectPrevious::default(), window, cx)) .unwrap(); cx.assert_editor_state("abc\n«abcˇ» abc\ndefabc\nabc"); - cx.update_editor(|e, cx| e.select_previous(&SelectPrevious::default(), cx)) + cx.update_editor(|e, window, cx| e.select_previous(&SelectPrevious::default(), window, cx)) .unwrap(); cx.assert_editor_state("«abcˇ»\n«abcˇ» abc\ndefabc\nabc"); - cx.update_editor(|view, cx| view.undo_selection(&UndoSelection, cx)); + cx.update_editor(|editor, window, cx| editor.undo_selection(&UndoSelection, window, cx)); cx.assert_editor_state("abc\n«abcˇ» abc\ndefabc\nabc"); - cx.update_editor(|view, cx| view.redo_selection(&RedoSelection, cx)); + cx.update_editor(|editor, window, cx| editor.redo_selection(&RedoSelection, window, cx)); cx.assert_editor_state("«abcˇ»\n«abcˇ» abc\ndefabc\nabc"); - cx.update_editor(|e, cx| e.select_previous(&SelectPrevious::default(), cx)) + cx.update_editor(|e, window, cx| e.select_previous(&SelectPrevious::default(), window, cx)) .unwrap(); cx.assert_editor_state("«abcˇ»\n«abcˇ» abc\ndefabc\n«abcˇ»"); - cx.update_editor(|e, cx| e.select_previous(&SelectPrevious::default(), cx)) + cx.update_editor(|e, window, cx| e.select_previous(&SelectPrevious::default(), window, cx)) .unwrap(); cx.assert_editor_state("«abcˇ»\n«abcˇ» abc\ndef«abcˇ»\n«abcˇ»"); - cx.update_editor(|e, cx| e.select_previous(&SelectPrevious::default(), cx)) + cx.update_editor(|e, window, cx| e.select_previous(&SelectPrevious::default(), window, cx)) .unwrap(); cx.assert_editor_state("«abcˇ»\n«abcˇ» «abcˇ»\ndef«abcˇ»\n«abcˇ»"); } @@ -5241,7 +5357,7 @@ let foo = 2; let foo = ˇ2;"#, ); - cx.update_editor(|e, cx| e.select_previous(&SelectPrevious::default(), cx)) + cx.update_editor(|e, window, cx| e.select_previous(&SelectPrevious::default(), window, cx)) .unwrap(); cx.assert_editor_state( r#"let foo = 2; @@ -5252,7 +5368,7 @@ let foo = «2ˇ»;"#, ); // noop for multiple selections with different contents - cx.update_editor(|e, cx| e.select_previous(&SelectPrevious::default(), cx)) + cx.update_editor(|e, window, cx| e.select_previous(&SelectPrevious::default(), window, cx)) .unwrap(); cx.assert_editor_state( r#"let foo = 2; @@ -5270,25 +5386,25 @@ async fn test_select_previous_with_single_selection(cx: &mut gpui::TestAppContex let mut cx = EditorTestContext::new(cx).await; cx.set_state("abc\n«ˇabc» abc\ndefabc\nabc"); - cx.update_editor(|e, cx| e.select_previous(&SelectPrevious::default(), cx)) + cx.update_editor(|e, window, cx| e.select_previous(&SelectPrevious::default(), window, cx)) .unwrap(); cx.assert_editor_state("«abcˇ»\n«ˇabc» abc\ndefabc\nabc"); - cx.update_editor(|e, cx| e.select_previous(&SelectPrevious::default(), cx)) + cx.update_editor(|e, window, cx| e.select_previous(&SelectPrevious::default(), window, cx)) .unwrap(); cx.assert_editor_state("«abcˇ»\n«ˇabc» abc\ndefabc\n«abcˇ»"); - cx.update_editor(|view, cx| view.undo_selection(&UndoSelection, cx)); + cx.update_editor(|editor, window, cx| editor.undo_selection(&UndoSelection, window, cx)); cx.assert_editor_state("«abcˇ»\n«ˇabc» abc\ndefabc\nabc"); - cx.update_editor(|view, cx| view.redo_selection(&RedoSelection, cx)); + cx.update_editor(|editor, window, cx| editor.redo_selection(&RedoSelection, window, cx)); cx.assert_editor_state("«abcˇ»\n«ˇabc» abc\ndefabc\n«abcˇ»"); - cx.update_editor(|e, cx| e.select_previous(&SelectPrevious::default(), cx)) + cx.update_editor(|e, window, cx| e.select_previous(&SelectPrevious::default(), window, cx)) .unwrap(); cx.assert_editor_state("«abcˇ»\n«ˇabc» abc\ndef«abcˇ»\n«abcˇ»"); - cx.update_editor(|e, cx| e.select_previous(&SelectPrevious::default(), cx)) + cx.update_editor(|e, window, cx| e.select_previous(&SelectPrevious::default(), window, cx)) .unwrap(); cx.assert_editor_state("«abcˇ»\n«ˇabc» «abcˇ»\ndef«abcˇ»\n«abcˇ»"); } @@ -5311,23 +5427,23 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { "# .unindent(); - let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); - let (editor, cx) = cx.add_window_view(|cx| build_editor(buffer, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(language, cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); + let (editor, cx) = cx.add_window_view(|window, cx| build_editor(buffer, window, cx)); editor - .condition::(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) + .condition::(cx, |editor, cx| !editor.buffer.read(cx).is_parsing(cx)) .await; - editor.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + editor.update_in(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(0), 25)..DisplayPoint::new(DisplayRow(0), 25), DisplayPoint::new(DisplayRow(2), 24)..DisplayPoint::new(DisplayRow(2), 12), DisplayPoint::new(DisplayRow(3), 18)..DisplayPoint::new(DisplayRow(3), 18), ]); }); - view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx); + editor.select_larger_syntax_node(&SelectLargerSyntaxNode, window, cx); }); editor.update(cx, |editor, cx| { assert_text_with_selections( @@ -5343,8 +5459,8 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { ); }); - editor.update(cx, |view, cx| { - view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx); + editor.update_in(cx, |editor, window, cx| { + editor.select_larger_syntax_node(&SelectLargerSyntaxNode, window, cx); }); editor.update(cx, |editor, cx| { assert_text_with_selections( @@ -5360,25 +5476,25 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { ); }); - editor.update(cx, |view, cx| { - view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx); + editor.update_in(cx, |editor, window, cx| { + editor.select_larger_syntax_node(&SelectLargerSyntaxNode, window, cx); }); assert_eq!( - editor.update(cx, |view, cx| view.selections.display_ranges(cx)), + editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)), &[DisplayPoint::new(DisplayRow(5), 0)..DisplayPoint::new(DisplayRow(0), 0)] ); // Trying to expand the selected syntax node one more time has no effect. - editor.update(cx, |view, cx| { - view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx); + editor.update_in(cx, |editor, window, cx| { + editor.select_larger_syntax_node(&SelectLargerSyntaxNode, window, cx); }); assert_eq!( - editor.update(cx, |view, cx| view.selections.display_ranges(cx)), + editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)), &[DisplayPoint::new(DisplayRow(5), 0)..DisplayPoint::new(DisplayRow(0), 0)] ); - editor.update(cx, |view, cx| { - view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx); + editor.update_in(cx, |editor, window, cx| { + editor.select_smaller_syntax_node(&SelectSmallerSyntaxNode, window, cx); }); editor.update(cx, |editor, cx| { assert_text_with_selections( @@ -5394,8 +5510,8 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { ); }); - editor.update(cx, |view, cx| { - view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx); + editor.update_in(cx, |editor, window, cx| { + editor.select_smaller_syntax_node(&SelectSmallerSyntaxNode, window, cx); }); editor.update(cx, |editor, cx| { assert_text_with_selections( @@ -5411,8 +5527,8 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { ); }); - editor.update(cx, |view, cx| { - view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx); + editor.update_in(cx, |editor, window, cx| { + editor.select_smaller_syntax_node(&SelectSmallerSyntaxNode, window, cx); }); editor.update(cx, |editor, cx| { assert_text_with_selections( @@ -5429,10 +5545,10 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { }); // Trying to shrink the selected syntax node one more time has no effect. - editor.update(cx, |view, cx| { - view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx); + editor.update_in(cx, |editor, window, cx| { + editor.select_smaller_syntax_node(&SelectSmallerSyntaxNode, window, cx); }); - editor.update(cx, |editor, cx| { + editor.update_in(cx, |editor, _, cx| { assert_text_with_selections( editor, indoc! {r#" @@ -5448,8 +5564,8 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { // Ensure that we keep expanding the selection if the larger selection starts or ends within // a fold. - editor.update(cx, |view, cx| { - view.fold_creases( + editor.update_in(cx, |editor, window, cx| { + editor.fold_creases( vec![ Crease::simple( Point::new(0, 21)..Point::new(0, 24), @@ -5461,9 +5577,10 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { ), ], true, + window, cx, ); - view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx); + editor.select_larger_syntax_node(&SelectLargerSyntaxNode, window, cx); }); editor.update(cx, |editor, cx| { assert_text_with_selections( @@ -5528,8 +5645,8 @@ async fn test_fold_function_bodies(cx: &mut gpui::TestAppContext) { let mut cx = EditorLspTestContext::new_rust(Default::default(), cx).await; cx.set_state(&text); cx.set_diff_base(&base_text); - cx.update_editor(|editor, cx| { - editor.expand_all_diff_hunks(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.expand_all_diff_hunks(&Default::default(), window, cx); }); cx.assert_state_with_diff( @@ -5577,8 +5694,8 @@ async fn test_fold_function_bodies(cx: &mut gpui::TestAppContext) { " .unindent(); - cx.update_editor(|editor, cx| { - editor.fold_function_bodies(&FoldFunctionBodies, cx); + cx.update_editor(|editor, window, cx| { + editor.fold_function_bodies(&FoldFunctionBodies, window, cx); assert_eq!(editor.display_text(cx), expected_display_text); }); } @@ -5624,16 +5741,16 @@ async fn test_autoindent(cx: &mut gpui::TestAppContext) { let text = "fn a() {}"; - let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); - let (editor, cx) = cx.add_window_view(|cx| build_editor(buffer, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(language, cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); + let (editor, cx) = cx.add_window_view(|window, cx| build_editor(buffer, window, cx)); editor .condition::(cx, |editor, cx| !editor.buffer.read(cx).is_parsing(cx)) .await; - editor.update(cx, |editor, cx| { - editor.change_selections(None, cx, |s| s.select_ranges([5..5, 8..8, 9..9])); - editor.newline(&Newline, cx); + editor.update_in(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| s.select_ranges([5..5, 8..8, 9..9])); + editor.newline(&Newline, window, cx); assert_eq!(editor.text(cx), "fn a(\n \n) {\n \n}\n"); assert_eq!( editor.selections.ranges(cx), @@ -5663,8 +5780,8 @@ async fn test_autoindent_selections(cx: &mut gpui::TestAppContext) { } "}); - cx.update_editor(|editor, cx| { - editor.autoindent(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.autoindent(&Default::default(), window, cx); }); cx.assert_editor_state(indoc! {" @@ -5695,7 +5812,7 @@ async fn test_autoindent_selections(cx: &mut gpui::TestAppContext) { "}], ); - let buffer = cx.update_editor(|editor, cx| { + let buffer = cx.update_editor(|editor, _, cx| { let buffer = editor.buffer().update(cx, |buffer, _| { buffer.all_buffers().iter().next().unwrap().clone() }); @@ -5704,13 +5821,13 @@ async fn test_autoindent_selections(cx: &mut gpui::TestAppContext) { }); cx.run_until_parked(); - cx.update_editor(|editor, cx| { - editor.select_all(&Default::default(), cx); - editor.autoindent(&Default::default(), cx) + cx.update_editor(|editor, window, cx| { + editor.select_all(&Default::default(), window, cx); + editor.autoindent(&Default::default(), window, cx) }); cx.run_until_parked(); - cx.update(|cx| { + cx.update(|_, cx| { pretty_assertions::assert_eq!( buffer.read(cx).text(), indoc! { " @@ -5805,10 +5922,10 @@ async fn test_autoclose_and_auto_surround_pairs(cx: &mut gpui::TestAppContext) { ); // autoclose multiple nested brackets at multiple cursors - cx.update_editor(|view, cx| { - view.handle_input("{", cx); - view.handle_input("{", cx); - view.handle_input("{", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input("{", window, cx); + editor.handle_input("{", window, cx); + editor.handle_input("{", window, cx); }); cx.assert_editor_state( &" @@ -5820,8 +5937,8 @@ async fn test_autoclose_and_auto_surround_pairs(cx: &mut gpui::TestAppContext) { ); // insert a different closing bracket - cx.update_editor(|view, cx| { - view.handle_input(")", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input(")", window, cx); }); cx.assert_editor_state( &" @@ -5833,11 +5950,11 @@ async fn test_autoclose_and_auto_surround_pairs(cx: &mut gpui::TestAppContext) { ); // skip over the auto-closed brackets when typing a closing bracket - cx.update_editor(|view, cx| { - view.move_right(&MoveRight, cx); - view.handle_input("}", cx); - view.handle_input("}", cx); - view.handle_input("}", cx); + cx.update_editor(|editor, window, cx| { + editor.move_right(&MoveRight, window, cx); + editor.handle_input("}", window, cx); + editor.handle_input("}", window, cx); + editor.handle_input("}", window, cx); }); cx.assert_editor_state( &" @@ -5856,9 +5973,9 @@ async fn test_autoclose_and_auto_surround_pairs(cx: &mut gpui::TestAppContext) { " .unindent(), ); - cx.update_editor(|view, cx| { - view.handle_input("/", cx); - view.handle_input("*", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input("/", window, cx); + editor.handle_input("*", window, cx); }); cx.assert_editor_state( &" @@ -5877,7 +5994,7 @@ async fn test_autoclose_and_auto_surround_pairs(cx: &mut gpui::TestAppContext) { " .unindent(), ); - cx.update_editor(|view, cx| view.handle_input("*", cx)); + cx.update_editor(|editor, window, cx| editor.handle_input("*", window, cx)); cx.assert_editor_state( &" /*ˇ */ @@ -5889,34 +6006,34 @@ async fn test_autoclose_and_auto_surround_pairs(cx: &mut gpui::TestAppContext) { // Don't autoclose if the next character isn't whitespace and isn't // listed in the language's "autoclose_before" section. cx.set_state("ˇa b"); - cx.update_editor(|view, cx| view.handle_input("{", cx)); + cx.update_editor(|editor, window, cx| editor.handle_input("{", window, cx)); cx.assert_editor_state("{ˇa b"); // Don't autoclose if `close` is false for the bracket pair cx.set_state("ˇ"); - cx.update_editor(|view, cx| view.handle_input("[", cx)); + cx.update_editor(|editor, window, cx| editor.handle_input("[", window, cx)); cx.assert_editor_state("[ˇ"); // Surround with brackets if text is selected cx.set_state("«aˇ» b"); - cx.update_editor(|view, cx| view.handle_input("{", cx)); + cx.update_editor(|editor, window, cx| editor.handle_input("{", window, cx)); cx.assert_editor_state("{«aˇ»} b"); // Autclose pair where the start and end characters are the same cx.set_state("aˇ"); - cx.update_editor(|view, cx| view.handle_input("\"", cx)); + cx.update_editor(|editor, window, cx| editor.handle_input("\"", window, cx)); cx.assert_editor_state("a\"ˇ\""); - cx.update_editor(|view, cx| view.handle_input("\"", cx)); + cx.update_editor(|editor, window, cx| editor.handle_input("\"", window, cx)); cx.assert_editor_state("a\"\"ˇ"); // Don't autoclose pair if autoclose is disabled cx.set_state("ˇ"); - cx.update_editor(|view, cx| view.handle_input("<", cx)); + cx.update_editor(|editor, window, cx| editor.handle_input("<", window, cx)); cx.assert_editor_state("<ˇ"); // Surround with brackets if text is selected and auto_surround is enabled, even if autoclose is disabled cx.set_state("«aˇ» b"); - cx.update_editor(|view, cx| view.handle_input("<", cx)); + cx.update_editor(|editor, window, cx| editor.handle_input("<", window, cx)); cx.assert_editor_state("<«aˇ»> b"); } @@ -5977,11 +6094,11 @@ async fn test_always_treat_brackets_as_autoclosed_skip_over(cx: &mut gpui::TestA ); // ensure only matching closing brackets are skipped over - cx.update_editor(|view, cx| { - view.handle_input("}", cx); - view.move_left(&MoveLeft, cx); - view.handle_input(")", cx); - view.move_left(&MoveLeft, cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input("}", window, cx); + editor.move_left(&MoveLeft, window, cx); + editor.handle_input(")", window, cx); + editor.move_left(&MoveLeft, window, cx); }); cx.assert_editor_state( &" @@ -5993,9 +6110,9 @@ async fn test_always_treat_brackets_as_autoclosed_skip_over(cx: &mut gpui::TestA ); // skip-over closing brackets at multiple cursors - cx.update_editor(|view, cx| { - view.handle_input(")", cx); - view.handle_input("}", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input(")", window, cx); + editor.handle_input("}", window, cx); }); cx.assert_editor_state( &" @@ -6007,10 +6124,10 @@ async fn test_always_treat_brackets_as_autoclosed_skip_over(cx: &mut gpui::TestA ); // ignore non-close brackets - cx.update_editor(|view, cx| { - view.handle_input("]", cx); - view.move_left(&MoveLeft, cx); - view.handle_input("]", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input("]", window, cx); + editor.move_left(&MoveLeft, window, cx); + editor.handle_input("]", window, cx); }); cx.assert_editor_state( &" @@ -6121,8 +6238,8 @@ async fn test_autoclose_with_embedded_language(cx: &mut gpui::TestAppContext) { ); // Precondition: different languages are active at different locations. - cx.update_editor(|editor, cx| { - let snapshot = editor.snapshot(cx); + cx.update_editor(|editor, window, cx| { + let snapshot = editor.snapshot(window, cx); let cursors = editor.selections.ranges::(cx); let languages = cursors .iter() @@ -6135,9 +6252,9 @@ async fn test_autoclose_with_embedded_language(cx: &mut gpui::TestAppContext) { }); // Angle brackets autoclose in HTML, but not JavaScript. - cx.update_editor(|editor, cx| { - editor.handle_input("<", cx); - editor.handle_input("a", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input("<", window, cx); + editor.handle_input("a", window, cx); }); cx.assert_editor_state( &r#" @@ -6151,11 +6268,11 @@ async fn test_autoclose_with_embedded_language(cx: &mut gpui::TestAppContext) { ); // Curly braces and parens autoclose in both HTML and JavaScript. - cx.update_editor(|editor, cx| { - editor.handle_input(" b=", cx); - editor.handle_input("{", cx); - editor.handle_input("c", cx); - editor.handle_input("(", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input(" b=", window, cx); + editor.handle_input("{", window, cx); + editor.handle_input("c", window, cx); + editor.handle_input("(", window, cx); }); cx.assert_editor_state( &r#" @@ -6169,10 +6286,10 @@ async fn test_autoclose_with_embedded_language(cx: &mut gpui::TestAppContext) { ); // Brackets that were already autoclosed are skipped. - cx.update_editor(|editor, cx| { - editor.handle_input(")", cx); - editor.handle_input("d", cx); - editor.handle_input("}", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input(")", window, cx); + editor.handle_input("d", window, cx); + editor.handle_input("}", window, cx); }); cx.assert_editor_state( &r#" @@ -6184,8 +6301,8 @@ async fn test_autoclose_with_embedded_language(cx: &mut gpui::TestAppContext) { "# .unindent(), ); - cx.update_editor(|editor, cx| { - editor.handle_input(">", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input(">", window, cx); }); cx.assert_editor_state( &r#" @@ -6210,8 +6327,8 @@ async fn test_autoclose_with_embedded_language(cx: &mut gpui::TestAppContext) { .unindent(), ); - cx.update_editor(|editor, cx| { - editor.handle_input("<", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input("<", window, cx); }); cx.assert_editor_state( &r#" @@ -6225,8 +6342,8 @@ async fn test_autoclose_with_embedded_language(cx: &mut gpui::TestAppContext) { ); // When backspacing, the closing angle brackets are removed. - cx.update_editor(|editor, cx| { - editor.backspace(&Backspace, cx); + cx.update_editor(|editor, window, cx| { + editor.backspace(&Backspace, window, cx); }); cx.assert_editor_state( &r#" @@ -6240,9 +6357,9 @@ async fn test_autoclose_with_embedded_language(cx: &mut gpui::TestAppContext) { ); // Block comments autoclose in JavaScript, but not HTML. - cx.update_editor(|editor, cx| { - editor.handle_input("/", cx); - editor.handle_input("*", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input("/", window, cx); + editor.handle_input("*", window, cx); }); cx.assert_editor_state( &r#" @@ -6293,8 +6410,8 @@ async fn test_autoclose_with_overrides(cx: &mut gpui::TestAppContext) { ); // Inserting a quotation mark. A closing quotation mark is automatically inserted. - cx.update_editor(|editor, cx| { - editor.handle_input("\"", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input("\"", window, cx); }); cx.assert_editor_state( &r#" @@ -6305,8 +6422,8 @@ async fn test_autoclose_with_overrides(cx: &mut gpui::TestAppContext) { // Inserting another quotation mark. The cursor moves across the existing // automatically-inserted quotation mark. - cx.update_editor(|editor, cx| { - editor.handle_input("\"", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input("\"", window, cx); }); cx.assert_editor_state( &r#" @@ -6324,12 +6441,12 @@ async fn test_autoclose_with_overrides(cx: &mut gpui::TestAppContext) { ); // Inserting a quotation mark inside of a string. A second quotation mark is not inserted. - cx.update_editor(|editor, cx| { - editor.handle_input("\"", cx); - editor.handle_input(" ", cx); - editor.move_left(&Default::default(), cx); - editor.handle_input("\\", cx); - editor.handle_input("\"", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input("\"", window, cx); + editor.handle_input(" ", window, cx); + editor.move_left(&Default::default(), window, cx); + editor.handle_input("\\", window, cx); + editor.handle_input("\"", window, cx); }); cx.assert_editor_state( &r#" @@ -6340,9 +6457,9 @@ async fn test_autoclose_with_overrides(cx: &mut gpui::TestAppContext) { // Inserting a closing quotation mark at the position of an automatically-inserted quotation // mark. Nothing is inserted. - cx.update_editor(|editor, cx| { - editor.move_right(&Default::default(), cx); - editor.handle_input("\"", cx); + cx.update_editor(|editor, window, cx| { + editor.move_right(&Default::default(), window, cx); + editor.handle_input("\"", window, cx); }); cx.assert_editor_state( &r#" @@ -6389,14 +6506,15 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { "# .unindent(); - let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); - let (view, cx) = cx.add_window_view(|cx| build_editor(buffer, cx)); - view.condition::(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) + let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(language, cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); + let (editor, cx) = cx.add_window_view(|window, cx| build_editor(buffer, window, cx)); + editor + .condition::(cx, |editor, cx| !editor.buffer.read(cx).is_parsing(cx)) .await; - view.update(cx, |view, cx| { - view.change_selections(None, cx, |s| { + editor.update_in(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_display_ranges([ DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1), DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 1), @@ -6404,11 +6522,11 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { ]) }); - view.handle_input("{", cx); - view.handle_input("{", cx); - view.handle_input("{", cx); + editor.handle_input("{", window, cx); + editor.handle_input("{", window, cx); + editor.handle_input("{", window, cx); assert_eq!( - view.text(cx), + editor.text(cx), " {{{a}}} {{{b}}} @@ -6417,7 +6535,7 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { .unindent() ); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), [ DisplayPoint::new(DisplayRow(0), 3)..DisplayPoint::new(DisplayRow(0), 4), DisplayPoint::new(DisplayRow(1), 3)..DisplayPoint::new(DisplayRow(1), 4), @@ -6425,11 +6543,11 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { ] ); - view.undo(&Undo, cx); - view.undo(&Undo, cx); - view.undo(&Undo, cx); + editor.undo(&Undo, window, cx); + editor.undo(&Undo, window, cx); + editor.undo(&Undo, window, cx); assert_eq!( - view.text(cx), + editor.text(cx), " a b @@ -6438,7 +6556,7 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { .unindent() ); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), [ DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1), DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 1), @@ -6448,9 +6566,9 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { // Ensure inserting the first character of a multi-byte bracket pair // doesn't surround the selections with the bracket. - view.handle_input("/", cx); + editor.handle_input("/", window, cx); assert_eq!( - view.text(cx), + editor.text(cx), " / / @@ -6459,7 +6577,7 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { .unindent() ); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), [ DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1), DisplayPoint::new(DisplayRow(1), 1)..DisplayPoint::new(DisplayRow(1), 1), @@ -6467,9 +6585,9 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { ] ); - view.undo(&Undo, cx); + editor.undo(&Undo, window, cx); assert_eq!( - view.text(cx), + editor.text(cx), " a b @@ -6478,7 +6596,7 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { .unindent() ); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), [ DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1), DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 1), @@ -6488,9 +6606,9 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { // Ensure inserting the last character of a multi-byte bracket pair // doesn't surround the selections with the bracket. - view.handle_input("*", cx); + editor.handle_input("*", window, cx); assert_eq!( - view.text(cx), + editor.text(cx), " * * @@ -6499,7 +6617,7 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { .unindent() ); assert_eq!( - view.selections.display_ranges(cx), + editor.selections.display_ranges(cx), [ DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1), DisplayPoint::new(DisplayRow(1), 1)..DisplayPoint::new(DisplayRow(1), 1), @@ -6538,15 +6656,15 @@ async fn test_delete_autoclose_pair(cx: &mut gpui::TestAppContext) { "# .unindent(); - let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); - let (editor, cx) = cx.add_window_view(|cx| build_editor(buffer, cx)); + let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(language, cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); + let (editor, cx) = cx.add_window_view(|window, cx| build_editor(buffer, window, cx)); editor - .condition::(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) + .condition::(cx, |editor, cx| !editor.buffer.read(cx).is_parsing(cx)) .await; - editor.update(cx, |editor, cx| { - editor.change_selections(None, cx, |s| { + editor.update_in(cx, |editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_ranges([ Point::new(0, 1)..Point::new(0, 1), Point::new(1, 1)..Point::new(1, 1), @@ -6554,9 +6672,9 @@ async fn test_delete_autoclose_pair(cx: &mut gpui::TestAppContext) { ]) }); - editor.handle_input("{", cx); - editor.handle_input("{", cx); - editor.handle_input("_", cx); + editor.handle_input("{", window, cx); + editor.handle_input("{", window, cx); + editor.handle_input("_", window, cx); assert_eq!( editor.text(cx), " @@ -6575,8 +6693,8 @@ async fn test_delete_autoclose_pair(cx: &mut gpui::TestAppContext) { ] ); - editor.backspace(&Default::default(), cx); - editor.backspace(&Default::default(), cx); + editor.backspace(&Default::default(), window, cx); + editor.backspace(&Default::default(), window, cx); assert_eq!( editor.text(cx), " @@ -6595,7 +6713,7 @@ async fn test_delete_autoclose_pair(cx: &mut gpui::TestAppContext) { ] ); - editor.delete_to_previous_word_start(&Default::default(), cx); + editor.delete_to_previous_word_start(&Default::default(), window, cx); assert_eq!( editor.text(cx), " @@ -6672,9 +6790,9 @@ async fn test_always_treat_brackets_as_autoclosed_delete(cx: &mut gpui::TestAppC .unindent(), ); - cx.update_editor(|view, cx| { - view.backspace(&Default::default(), cx); - view.backspace(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.backspace(&Default::default(), window, cx); + editor.backspace(&Default::default(), window, cx); }); cx.assert_editor_state( @@ -6686,14 +6804,14 @@ async fn test_always_treat_brackets_as_autoclosed_delete(cx: &mut gpui::TestAppC .unindent(), ); - cx.update_editor(|view, cx| { - view.handle_input("{", cx); - view.handle_input("{", cx); - view.move_right(&MoveRight, cx); - view.move_right(&MoveRight, cx); - view.move_left(&MoveLeft, cx); - view.move_left(&MoveLeft, cx); - view.backspace(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input("{", window, cx); + editor.handle_input("{", window, cx); + editor.move_right(&MoveRight, window, cx); + editor.move_right(&MoveRight, window, cx); + editor.move_left(&MoveLeft, window, cx); + editor.move_left(&MoveLeft, window, cx); + editor.backspace(&Default::default(), window, cx); }); cx.assert_editor_state( @@ -6705,8 +6823,8 @@ async fn test_always_treat_brackets_as_autoclosed_delete(cx: &mut gpui::TestAppC .unindent(), ); - cx.update_editor(|view, cx| { - view.backspace(&Default::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.backspace(&Default::default(), window, cx); }); cx.assert_editor_state( @@ -6728,59 +6846,59 @@ async fn test_auto_replace_emoji_shortcode(cx: &mut gpui::TestAppContext) { Some(tree_sitter_rust::LANGUAGE.into()), )); - let buffer = cx.new_model(|cx| Buffer::local("", cx).with_language(language, cx)); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); - let (editor, cx) = cx.add_window_view(|cx| build_editor(buffer, cx)); + let buffer = cx.new(|cx| Buffer::local("", cx).with_language(language, cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); + let (editor, cx) = cx.add_window_view(|window, cx| build_editor(buffer, window, cx)); editor - .condition::(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) + .condition::(cx, |editor, cx| !editor.buffer.read(cx).is_parsing(cx)) .await; - editor.update(cx, |editor, cx| { + editor.update_in(cx, |editor, window, cx| { editor.set_auto_replace_emoji_shortcode(true); - editor.handle_input("Hello ", cx); - editor.handle_input(":wave", cx); + editor.handle_input("Hello ", window, cx); + editor.handle_input(":wave", window, cx); assert_eq!(editor.text(cx), "Hello :wave".unindent()); - editor.handle_input(":", cx); + editor.handle_input(":", window, cx); assert_eq!(editor.text(cx), "Hello 👋".unindent()); - editor.handle_input(" :smile", cx); + editor.handle_input(" :smile", window, cx); assert_eq!(editor.text(cx), "Hello 👋 :smile".unindent()); - editor.handle_input(":", cx); + editor.handle_input(":", window, cx); assert_eq!(editor.text(cx), "Hello 👋 😄".unindent()); // Ensure shortcode gets replaced when it is part of a word that only consists of emojis - editor.handle_input(":wave", cx); + editor.handle_input(":wave", window, cx); assert_eq!(editor.text(cx), "Hello 👋 😄:wave".unindent()); - editor.handle_input(":", cx); + editor.handle_input(":", window, cx); assert_eq!(editor.text(cx), "Hello 👋 😄👋".unindent()); - editor.handle_input(":1", cx); + editor.handle_input(":1", window, cx); assert_eq!(editor.text(cx), "Hello 👋 😄👋:1".unindent()); - editor.handle_input(":", cx); + editor.handle_input(":", window, cx); assert_eq!(editor.text(cx), "Hello 👋 😄👋:1:".unindent()); // Ensure shortcode does not get replaced when it is part of a word - editor.handle_input(" Test:wave", cx); + editor.handle_input(" Test:wave", window, cx); assert_eq!(editor.text(cx), "Hello 👋 😄👋:1: Test:wave".unindent()); - editor.handle_input(":", cx); + editor.handle_input(":", window, cx); assert_eq!(editor.text(cx), "Hello 👋 😄👋:1: Test:wave:".unindent()); editor.set_auto_replace_emoji_shortcode(false); // Ensure shortcode does not get replaced when auto replace is off - editor.handle_input(" :wave", cx); + editor.handle_input(" :wave", window, cx); assert_eq!( editor.text(cx), "Hello 👋 😄👋:1: Test:wave: :wave".unindent() ); - editor.handle_input(":", cx); + editor.handle_input(":", window, cx); assert_eq!( editor.text(cx), "Hello 👋 😄👋:1: Test:wave: :wave:".unindent() @@ -6800,16 +6918,16 @@ async fn test_snippet_placeholder_choices(cx: &mut gpui::TestAppContext) { ); let buffer = cx.update(|cx| MultiBuffer::build_simple(&text, cx)); - let (editor, cx) = cx.add_window_view(|cx| build_editor(buffer, cx)); + let (editor, cx) = cx.add_window_view(|window, cx| build_editor(buffer, window, cx)); - _ = editor.update(cx, |editor, cx| { + _ = editor.update_in(cx, |editor, window, cx| { let snippet = Snippet::parse("type ${1|,i32,u32|} = $2").unwrap(); editor - .insert_snippet(&insertion_ranges, snippet, cx) + .insert_snippet(&insertion_ranges, snippet, window, cx) .unwrap(); - fn assert(editor: &mut Editor, cx: &mut ViewContext, marked_text: &str) { + fn assert(editor: &mut Editor, cx: &mut Context, marked_text: &str) { let (expected_text, selection_ranges) = marked_text_ranges(marked_text, false); assert_eq!(editor.text(cx), expected_text); assert_eq!(editor.selections.ranges::(cx), selection_ranges); @@ -6841,16 +6959,16 @@ async fn test_snippets(cx: &mut gpui::TestAppContext) { ); let buffer = cx.update(|cx| MultiBuffer::build_simple(&text, cx)); - let (editor, cx) = cx.add_window_view(|cx| build_editor(buffer, cx)); + let (editor, cx) = cx.add_window_view(|window, cx| build_editor(buffer, window, cx)); - editor.update(cx, |editor, cx| { + editor.update_in(cx, |editor, window, cx| { let snippet = Snippet::parse("f(${1:one}, ${2:two}, ${1:three})$0").unwrap(); editor - .insert_snippet(&insertion_ranges, snippet, cx) + .insert_snippet(&insertion_ranges, snippet, window, cx) .unwrap(); - fn assert(editor: &mut Editor, cx: &mut ViewContext, marked_text: &str) { + fn assert(editor: &mut Editor, cx: &mut Context, marked_text: &str) { let (expected_text, selection_ranges) = marked_text_ranges(marked_text, false); assert_eq!(editor.text(cx), expected_text); assert_eq!(editor.selections.ranges::(cx), selection_ranges); @@ -6867,7 +6985,7 @@ async fn test_snippets(cx: &mut gpui::TestAppContext) { ); // Can't move earlier than the first tab stop - assert!(!editor.move_to_prev_snippet_tabstop(cx)); + assert!(!editor.move_to_prev_snippet_tabstop(window, cx)); assert( editor, cx, @@ -6878,7 +6996,7 @@ async fn test_snippets(cx: &mut gpui::TestAppContext) { "}, ); - assert!(editor.move_to_next_snippet_tabstop(cx)); + assert!(editor.move_to_next_snippet_tabstop(window, cx)); assert( editor, cx, @@ -6889,7 +7007,7 @@ async fn test_snippets(cx: &mut gpui::TestAppContext) { "}, ); - editor.move_to_prev_snippet_tabstop(cx); + editor.move_to_prev_snippet_tabstop(window, cx); assert( editor, cx, @@ -6900,7 +7018,7 @@ async fn test_snippets(cx: &mut gpui::TestAppContext) { "}, ); - assert!(editor.move_to_next_snippet_tabstop(cx)); + assert!(editor.move_to_next_snippet_tabstop(window, cx)); assert( editor, cx, @@ -6910,7 +7028,7 @@ async fn test_snippets(cx: &mut gpui::TestAppContext) { a.f(one, «two», three) b "}, ); - assert!(editor.move_to_next_snippet_tabstop(cx)); + assert!(editor.move_to_next_snippet_tabstop(window, cx)); assert( editor, cx, @@ -6922,7 +7040,7 @@ async fn test_snippets(cx: &mut gpui::TestAppContext) { ); // As soon as the last tab stop is reached, snippet state is gone - editor.move_to_prev_snippet_tabstop(cx); + editor.move_to_prev_snippet_tabstop(window, cx); assert( editor, cx, @@ -6962,17 +7080,22 @@ async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) { .await .unwrap(); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); - let (editor, cx) = - cx.add_window_view(|cx| build_editor_with_project(project.clone(), buffer, cx)); - editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); + let (editor, cx) = cx.add_window_view(|window, cx| { + build_editor_with_project(project.clone(), buffer, window, cx) + }); + editor.update_in(cx, |editor, window, cx| { + editor.set_text("one\ntwo\nthree\n", window, cx) + }); assert!(cx.read(|cx| editor.is_dirty(cx))); cx.executor().start_waiting(); let fake_server = fake_servers.next().await.unwrap(); let save = editor - .update(cx, |editor, cx| editor.save(true, project.clone(), cx)) + .update_in(cx, |editor, window, cx| { + editor.save(true, project.clone(), window, cx) + }) .unwrap(); fake_server .handle_request::(move |params, _| async move { @@ -6997,7 +7120,9 @@ async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) { ); assert!(!cx.read(|cx| editor.is_dirty(cx))); - editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx)); + editor.update_in(cx, |editor, window, cx| { + editor.set_text("one\ntwo\nthree\n", window, cx) + }); assert!(cx.read(|cx| editor.is_dirty(cx))); // Ensure we can still save even if formatting hangs. @@ -7010,7 +7135,9 @@ async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) { unreachable!() }); let save = editor - .update(cx, |editor, cx| editor.save(true, project.clone(), cx)) + .update_in(cx, |editor, window, cx| { + editor.save(true, project.clone(), window, cx) + }) .unwrap(); cx.executor().advance_clock(super::FORMAT_TIMEOUT); cx.executor().start_waiting(); @@ -7023,7 +7150,9 @@ async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) { // For non-dirty buffer, no formatting request should be sent let save = editor - .update(cx, |editor, cx| editor.save(true, project.clone(), cx)) + .update_in(cx, |editor, window, cx| { + editor.save(true, project.clone(), window, cx) + }) .unwrap(); let _pending_format_request = fake_server .handle_request::(move |_, _| async move { @@ -7044,10 +7173,14 @@ async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) { ); }); - editor.update(cx, |editor, cx| editor.set_text("somehting_new\n", cx)); + editor.update_in(cx, |editor, window, cx| { + editor.set_text("somehting_new\n", window, cx) + }); assert!(cx.read(|cx| editor.is_dirty(cx))); let save = editor - .update(cx, |editor, cx| editor.save(true, project.clone(), cx)) + .update_in(cx, |editor, window, cx| { + editor.save(true, project.clone(), window, cx) + }) .unwrap(); fake_server .handle_request::(move |params, _| async move { @@ -7098,7 +7231,7 @@ async fn test_multibuffer_format_during_save(cx: &mut gpui::TestAppContext) { .await; let project = Project::test(fs, ["/a".as_ref()], cx).await; - let workspace = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); + let workspace = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx)); let cx = &mut VisualTestContext::from_window(*workspace.deref(), cx); let language_registry = project.read_with(cx, |project, _| project.languages().clone()); @@ -7140,7 +7273,7 @@ async fn test_multibuffer_format_during_save(cx: &mut gpui::TestAppContext) { .await .unwrap(); - let multi_buffer = cx.new_model(|cx| { + let multi_buffer = cx.new(|cx| { let mut multi_buffer = MultiBuffer::new(ReadWrite); multi_buffer.push_excerpts( buffer_1.clone(), @@ -7198,26 +7331,29 @@ async fn test_multibuffer_format_during_save(cx: &mut gpui::TestAppContext) { ); multi_buffer }); - let multi_buffer_editor = cx.new_view(|cx| { + let multi_buffer_editor = cx.new_window_model(|window, cx| { Editor::new( EditorMode::Full, multi_buffer, Some(project.clone()), true, + window, cx, ) }); - multi_buffer_editor.update(cx, |editor, cx| { - editor.change_selections(Some(Autoscroll::Next), cx, |s| s.select_ranges(Some(1..2))); - editor.insert("|one|two|three|", cx); + multi_buffer_editor.update_in(cx, |editor, window, cx| { + editor.change_selections(Some(Autoscroll::Next), window, cx, |s| { + s.select_ranges(Some(1..2)) + }); + editor.insert("|one|two|three|", window, cx); }); assert!(cx.read(|cx| multi_buffer_editor.is_dirty(cx))); - multi_buffer_editor.update(cx, |editor, cx| { - editor.change_selections(Some(Autoscroll::Next), cx, |s| { + multi_buffer_editor.update_in(cx, |editor, window, cx| { + editor.change_selections(Some(Autoscroll::Next), window, cx, |s| { s.select_ranges(Some(60..70)) }); - editor.insert("|four|five|six|", cx); + editor.insert("|four|five|six|", window, cx); }); assert!(cx.read(|cx| multi_buffer_editor.is_dirty(cx))); @@ -7248,7 +7384,9 @@ async fn test_multibuffer_format_during_save(cx: &mut gpui::TestAppContext) { cx.executor().start_waiting(); let save = multi_buffer_editor - .update(cx, |editor, cx| editor.save(true, project.clone(), cx)) + .update_in(cx, |editor, window, cx| { + editor.save(true, project.clone(), window, cx) + }) .unwrap(); let fake_server = fake_servers.next().await.unwrap(); @@ -7316,17 +7454,22 @@ async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) { .await .unwrap(); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); - let (editor, cx) = - cx.add_window_view(|cx| build_editor_with_project(project.clone(), buffer, cx)); - editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); + let (editor, cx) = cx.add_window_view(|window, cx| { + build_editor_with_project(project.clone(), buffer, window, cx) + }); + editor.update_in(cx, |editor, window, cx| { + editor.set_text("one\ntwo\nthree\n", window, cx) + }); assert!(cx.read(|cx| editor.is_dirty(cx))); cx.executor().start_waiting(); let fake_server = fake_servers.next().await.unwrap(); let save = editor - .update(cx, |editor, cx| editor.save(true, project.clone(), cx)) + .update_in(cx, |editor, window, cx| { + editor.save(true, project.clone(), window, cx) + }) .unwrap(); fake_server .handle_request::(move |params, _| async move { @@ -7350,7 +7493,9 @@ async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) { ); assert!(!cx.read(|cx| editor.is_dirty(cx))); - editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx)); + editor.update_in(cx, |editor, window, cx| { + editor.set_text("one\ntwo\nthree\n", window, cx) + }); assert!(cx.read(|cx| editor.is_dirty(cx))); // Ensure we can still save even if formatting hangs. @@ -7365,7 +7510,9 @@ async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) { }, ); let save = editor - .update(cx, |editor, cx| editor.save(true, project.clone(), cx)) + .update_in(cx, |editor, window, cx| { + editor.save(true, project.clone(), window, cx) + }) .unwrap(); cx.executor().advance_clock(super::FORMAT_TIMEOUT); cx.executor().start_waiting(); @@ -7378,7 +7525,9 @@ async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) { // For non-dirty buffer, no formatting request should be sent let save = editor - .update(cx, |editor, cx| editor.save(true, project.clone(), cx)) + .update_in(cx, |editor, window, cx| { + editor.save(true, project.clone(), window, cx) + }) .unwrap(); let _pending_format_request = fake_server .handle_request::(move |_, _| async move { @@ -7399,10 +7548,14 @@ async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) { ); }); - editor.update(cx, |editor, cx| editor.set_text("somehting_new\n", cx)); + editor.update_in(cx, |editor, window, cx| { + editor.set_text("somehting_new\n", window, cx) + }); assert!(cx.read(|cx| editor.is_dirty(cx))); let save = editor - .update(cx, |editor, cx| editor.save(true, project.clone(), cx)) + .update_in(cx, |editor, window, cx| { + editor.save(true, project.clone(), window, cx) + }) .unwrap(); fake_server .handle_request::(move |params, _| async move { @@ -7468,20 +7621,24 @@ async fn test_document_format_manual_trigger(cx: &mut gpui::TestAppContext) { .await .unwrap(); - let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx)); - let (editor, cx) = - cx.add_window_view(|cx| build_editor_with_project(project.clone(), buffer, cx)); - editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); + let (editor, cx) = cx.add_window_view(|window, cx| { + build_editor_with_project(project.clone(), buffer, window, cx) + }); + editor.update_in(cx, |editor, window, cx| { + editor.set_text("one\ntwo\nthree\n", window, cx) + }); cx.executor().start_waiting(); let fake_server = fake_servers.next().await.unwrap(); let format = editor - .update(cx, |editor, cx| { + .update_in(cx, |editor, window, cx| { editor.perform_format( project.clone(), FormatTrigger::Manual, FormatTarget::Buffers, + window, cx, ) }) @@ -7507,7 +7664,9 @@ async fn test_document_format_manual_trigger(cx: &mut gpui::TestAppContext) { "one, two\nthree\n" ); - editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx)); + editor.update_in(cx, |editor, window, cx| { + editor.set_text("one\ntwo\nthree\n", window, cx) + }); // Ensure we don't lock if formatting hangs. fake_server.handle_request::(move |params, _| async move { assert_eq!( @@ -7518,8 +7677,14 @@ async fn test_document_format_manual_trigger(cx: &mut gpui::TestAppContext) { unreachable!() }); let format = editor - .update(cx, |editor, cx| { - editor.perform_format(project, FormatTrigger::Manual, FormatTarget::Buffers, cx) + .update_in(cx, |editor, window, cx| { + editor.perform_format( + project, + FormatTrigger::Manual, + FormatTarget::Buffers, + window, + cx, + ) }) .unwrap(); cx.executor().advance_clock(super::FORMAT_TIMEOUT); @@ -7564,13 +7729,13 @@ async fn test_concurrent_format_requests(cx: &mut gpui::TestAppContext) { // Submit a format request. let format_1 = cx - .update_editor(|editor, cx| editor.format(&Format, cx)) + .update_editor(|editor, window, cx| editor.format(&Format, window, cx)) .unwrap(); cx.executor().run_until_parked(); // Submit a second format request. let format_2 = cx - .update_editor(|editor, cx| editor.format(&Format, cx)) + .update_editor(|editor, window, cx| editor.format(&Format, window, cx)) .unwrap(); cx.executor().run_until_parked(); @@ -7616,7 +7781,7 @@ async fn test_strip_whitespace_and_format_via_lsp(cx: &mut gpui::TestAppContext) // Submit a format request. let format = cx - .update_editor(|editor, cx| editor.format(&Format, cx)) + .update_editor(|editor, window, cx| editor.format(&Format, window, cx)) .unwrap(); // Record which buffer changes have been sent to the language server @@ -7801,8 +7966,8 @@ async fn test_handle_input_for_show_signature_help_auto_signature_help_true( .unindent(), ); - cx.update_editor(|view, cx| { - view.handle_input("(", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input("(", window, cx); }); cx.assert_editor_state( &" @@ -7837,7 +8002,7 @@ async fn test_handle_input_for_show_signature_help_auto_signature_help_true( cx.condition(|editor, _| editor.signature_help_state.is_shown()) .await; - cx.editor(|editor, _| { + cx.editor(|editor, _, _| { let signature_help_state = editor.signature_help_state.popover().cloned(); assert!(signature_help_state.is_some()); let ParsedMarkdown { @@ -7943,8 +8108,8 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut gpui: "# .unindent(), ); - cx.update_editor(|view, cx| { - view.handle_input("(", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input("(", window, cx); }); cx.assert_editor_state( &" @@ -7954,7 +8119,7 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut gpui: " .unindent(), ); - cx.editor(|editor, _| { + cx.editor(|editor, _, _| { assert!(editor.signature_help_state.task().is_none()); }); @@ -7979,7 +8144,7 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut gpui: }; // Ensure that signature_help is called when enabled afte edits - cx.update(|cx| { + cx.update(|_, cx| { cx.update_global::(|settings, cx| { settings.update_user_settings::(cx, |settings| { settings.auto_signature_help = Some(false); @@ -7995,8 +8160,8 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut gpui: "# .unindent(), ); - cx.update_editor(|view, cx| { - view.handle_input("(", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input("(", window, cx); }); cx.assert_editor_state( &" @@ -8009,7 +8174,7 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut gpui: handle_signature_help_request(&mut cx, mocked_response.clone()).await; cx.condition(|editor, _| editor.signature_help_state.is_shown()) .await; - cx.update_editor(|editor, _| { + cx.update_editor(|editor, _, _| { let signature_help_state = editor.signature_help_state.popover().cloned(); assert!(signature_help_state.is_some()); let ParsedMarkdown { @@ -8021,7 +8186,7 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut gpui: }); // Ensure that signature_help is called when auto signature help override is enabled - cx.update(|cx| { + cx.update(|_, cx| { cx.update_global::(|settings, cx| { settings.update_user_settings::(cx, |settings| { settings.auto_signature_help = Some(true); @@ -8037,8 +8202,8 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut gpui: "# .unindent(), ); - cx.update_editor(|view, cx| { - view.handle_input("(", cx); + cx.update_editor(|editor, window, cx| { + editor.handle_input("(", window, cx); }); cx.assert_editor_state( &" @@ -8051,7 +8216,7 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut gpui: handle_signature_help_request(&mut cx, mocked_response).await; cx.condition(|editor, _| editor.signature_help_state.is_shown()) .await; - cx.editor(|editor, _| { + cx.editor(|editor, _, _| { let signature_help_state = editor.signature_help_state.popover().cloned(); assert!(signature_help_state.is_some()); let ParsedMarkdown { @@ -8085,8 +8250,8 @@ async fn test_signature_help(cx: &mut gpui::TestAppContext) { .await; // A test that directly calls `show_signature_help` - cx.update_editor(|editor, cx| { - editor.show_signature_help(&ShowSignatureHelp, cx); + cx.update_editor(|editor, window, cx| { + editor.show_signature_help(&ShowSignatureHelp, window, cx); }); let mocked_response = lsp::SignatureHelp { @@ -8113,7 +8278,7 @@ async fn test_signature_help(cx: &mut gpui::TestAppContext) { cx.condition(|editor, _| editor.signature_help_state.is_shown()) .await; - cx.editor(|editor, _| { + cx.editor(|editor, _, _| { let signature_help_state = editor.signature_help_state.popover().cloned(); assert!(signature_help_state.is_some()); let ParsedMarkdown { @@ -8132,8 +8297,8 @@ async fn test_signature_help(cx: &mut gpui::TestAppContext) { fn sample(param1: u8, param2: u8) {} "}); - cx.update_editor(|editor, cx| { - editor.change_selections(None, cx, |s| s.select_ranges([0..0])); + cx.update_editor(|editor, window, cx| { + editor.change_selections(None, window, cx, |s| s.select_ranges([0..0])); }); let mocked_response = lsp::SignatureHelp { @@ -8146,7 +8311,7 @@ async fn test_signature_help(cx: &mut gpui::TestAppContext) { cx.condition(|editor, _| !editor.signature_help_state.is_shown()) .await; - cx.editor(|editor, _| { + cx.editor(|editor, _, _| { assert!(!editor.signature_help_state.is_shown()); }); @@ -8181,7 +8346,7 @@ async fn test_signature_help(cx: &mut gpui::TestAppContext) { handle_signature_help_request(&mut cx, mocked_response.clone()).await; cx.condition(|editor, _| editor.signature_help_state.is_shown()) .await; - cx.editor(|editor, _| { + cx.editor(|editor, _, _| { assert!(editor.signature_help_state.is_shown()); }); @@ -8219,8 +8384,8 @@ async fn test_signature_help(cx: &mut gpui::TestAppContext) { // When selecting a range, the popover is gone. // Avoid using `cx.set_state` to not actually edit the document, just change its selections. - cx.update_editor(|editor, cx| { - editor.change_selections(None, cx, |s| { + cx.update_editor(|editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_ranges(Some(Point::new(1, 25)..Point::new(1, 19))); }) }); @@ -8231,13 +8396,13 @@ async fn test_signature_help(cx: &mut gpui::TestAppContext) { fn sample(param1: u8, param2: u8) {} "}); - cx.editor(|editor, _| { + cx.editor(|editor, _, _| { assert!(!editor.signature_help_state.is_shown()); }); // When unselecting again, the popover is back if within the brackets. - cx.update_editor(|editor, cx| { - editor.change_selections(None, cx, |s| { + cx.update_editor(|editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_ranges(Some(Point::new(1, 19)..Point::new(1, 19))); }) }); @@ -8251,13 +8416,13 @@ async fn test_signature_help(cx: &mut gpui::TestAppContext) { handle_signature_help_request(&mut cx, mocked_response).await; cx.condition(|editor, _| editor.signature_help_state.is_shown()) .await; - cx.editor(|editor, _| { + cx.editor(|editor, _, _| { assert!(editor.signature_help_state.is_shown()); }); // Test to confirm that SignatureHelp does not appear after deselecting multiple ranges when it was hidden by pressing Escape. - cx.update_editor(|editor, cx| { - editor.change_selections(None, cx, |s| { + cx.update_editor(|editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_ranges(Some(Point::new(0, 0)..Point::new(0, 0))); s.select_ranges(Some(Point::new(1, 19)..Point::new(1, 19))); }) @@ -8292,13 +8457,13 @@ async fn test_signature_help(cx: &mut gpui::TestAppContext) { handle_signature_help_request(&mut cx, mocked_response.clone()).await; cx.condition(|editor, _| editor.signature_help_state.is_shown()) .await; - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, _, cx| { editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape); }); cx.condition(|editor, _| !editor.signature_help_state.is_shown()) .await; - cx.update_editor(|editor, cx| { - editor.change_selections(None, cx, |s| { + cx.update_editor(|editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_ranges(Some(Point::new(1, 25)..Point::new(1, 19))); }) }); @@ -8309,8 +8474,8 @@ async fn test_signature_help(cx: &mut gpui::TestAppContext) { fn sample(param1: u8, param2: u8) {} "}); - cx.update_editor(|editor, cx| { - editor.change_selections(None, cx, |s| { + cx.update_editor(|editor, window, cx| { + editor.change_selections(None, window, cx, |s| { s.select_ranges(Some(Point::new(1, 19)..Point::new(1, 19))); }) }); @@ -8381,25 +8546,25 @@ async fn test_completion(cx: &mut gpui::TestAppContext) { active_parameter: None, }, ); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, window, cx| { assert!( !editor.signature_help_state.is_shown(), "No signature help was called for" ); - editor.show_signature_help(&ShowSignatureHelp, cx); + editor.show_signature_help(&ShowSignatureHelp, window, cx); }); cx.run_until_parked(); - cx.update_editor(|editor, _| { + cx.update_editor(|editor, _, _| { assert!( !editor.signature_help_state.is_shown(), "No signature help should be shown when completions menu is open" ); }); - let apply_additional_edits = cx.update_editor(|editor, cx| { - editor.context_menu_next(&Default::default(), cx); + let apply_additional_edits = cx.update_editor(|editor, window, cx| { + editor.context_menu_next(&Default::default(), window, cx); editor - .confirm_completion(&ConfirmCompletion::default(), cx) + .confirm_completion(&ConfirmCompletion::default(), window, cx) .unwrap() }); cx.assert_editor_state(indoc! {" @@ -8447,9 +8612,9 @@ async fn test_completion(cx: &mut gpui::TestAppContext) { additional edit "}); cx.simulate_keystroke(" "); - assert!(cx.editor(|e, _| e.context_menu.borrow_mut().is_none())); + assert!(cx.editor(|e, _, _| e.context_menu.borrow_mut().is_none())); cx.simulate_keystroke("s"); - assert!(cx.editor(|e, _| e.context_menu.borrow_mut().is_none())); + assert!(cx.editor(|e, _, _| e.context_menu.borrow_mut().is_none())); cx.assert_editor_state(indoc! {" one.second_completion @@ -8491,9 +8656,9 @@ async fn test_completion(cx: &mut gpui::TestAppContext) { .await; assert_eq!(counter.load(atomic::Ordering::Acquire), 3); - let apply_additional_edits = cx.update_editor(|editor, cx| { + let apply_additional_edits = cx.update_editor(|editor, window, cx| { editor - .confirm_completion(&ConfirmCompletion::default(), cx) + .confirm_completion(&ConfirmCompletion::default(), window, cx) .unwrap() }); cx.assert_editor_state(indoc! {" @@ -8510,14 +8675,14 @@ async fn test_completion(cx: &mut gpui::TestAppContext) { }); cx.set_state("editorˇ"); cx.simulate_keystroke("."); - assert!(cx.editor(|e, _| e.context_menu.borrow_mut().is_none())); + assert!(cx.editor(|e, _, _| e.context_menu.borrow_mut().is_none())); cx.simulate_keystroke("c"); cx.simulate_keystroke("l"); cx.simulate_keystroke("o"); cx.assert_editor_state("editor.cloˇ"); - assert!(cx.editor(|e, _| e.context_menu.borrow_mut().is_none())); - cx.update_editor(|editor, cx| { - editor.show_completions(&ShowCompletions { trigger: None }, cx); + assert!(cx.editor(|e, _, _| e.context_menu.borrow_mut().is_none())); + cx.update_editor(|editor, window, cx| { + editor.show_completions(&ShowCompletions { trigger: None }, window, cx); }); handle_completion_request( &mut cx, @@ -8530,9 +8695,9 @@ async fn test_completion(cx: &mut gpui::TestAppContext) { .await; assert_eq!(counter.load(atomic::Ordering::Acquire), 4); - let apply_additional_edits = cx.update_editor(|editor, cx| { + let apply_additional_edits = cx.update_editor(|editor, window, cx| { editor - .confirm_completion(&ConfirmCompletion::default(), cx) + .confirm_completion(&ConfirmCompletion::default(), window, cx) .unwrap() }); cx.assert_editor_state("editor.closeˇ"); @@ -8602,10 +8767,10 @@ async fn test_multiline_completion(cx: &mut gpui::TestAppContext) { ..FakeLspAdapter::default() }, ); - let workspace = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); + let workspace = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx)); let cx = &mut VisualTestContext::from_window(*workspace, cx); let worktree_id = workspace - .update(cx, |workspace, cx| { + .update(cx, |workspace, _window, cx| { workspace.project().update(cx, |project, cx| { project.worktrees(cx).next().unwrap().read(cx).id() }) @@ -8618,8 +8783,8 @@ async fn test_multiline_completion(cx: &mut gpui::TestAppContext) { .await .unwrap(); let editor = workspace - .update(cx, |workspace, cx| { - workspace.open_path((worktree_id, "main.ts"), None, true, cx) + .update(cx, |workspace, window, cx| { + workspace.open_path((worktree_id, "main.ts"), None, true, window, cx) }) .unwrap() .await @@ -8734,10 +8899,10 @@ async fn test_multiline_completion(cx: &mut gpui::TestAppContext) { ]))) }); - editor.update(cx, |editor, cx| { - editor.focus(cx); - editor.move_to_end(&MoveToEnd, cx); - editor.handle_input(".", cx); + editor.update_in(cx, |editor, window, cx| { + cx.focus_self(window); + editor.move_to_end(&MoveToEnd, window, cx); + editor.handle_input(".", window, cx); }); cx.run_until_parked(); completion_handle.next().await.unwrap(); @@ -8812,7 +8977,7 @@ async fn test_completion_page_up_down_keys(cx: &mut gpui::TestAppContext) { cx.simulate_keystroke("."); cx.executor().run_until_parked(); - cx.update_editor(|editor, _| { + cx.update_editor(|editor, _, _| { if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() { assert_eq!(completion_menu_entries(&menu), &["first", "last"]); @@ -8821,8 +8986,8 @@ async fn test_completion_page_up_down_keys(cx: &mut gpui::TestAppContext) { } }); - cx.update_editor(|editor, cx| { - editor.move_page_down(&MovePageDown::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.move_page_down(&MovePageDown::default(), window, cx); if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() { assert!( @@ -8834,8 +8999,8 @@ async fn test_completion_page_up_down_keys(cx: &mut gpui::TestAppContext) { } }); - cx.update_editor(|editor, cx| { - editor.move_page_up(&MovePageUp::default(), cx); + cx.update_editor(|editor, window, cx| { + editor.move_page_up(&MovePageUp::default(), window, cx); if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() { assert!( @@ -8894,17 +9059,18 @@ async fn test_completion_sort(cx: &mut gpui::TestAppContext) { }); cx.set_state("rˇ"); cx.executor().run_until_parked(); - cx.update_editor(|editor, cx| { + cx.update_editor(|editor, window, cx| { editor.show_completions( &ShowCompletions { trigger: Some("r".into()), }, + window, cx, ); }); cx.executor().run_until_parked(); - cx.update_editor(|editor, _| { + cx.update_editor(|editor, _, _| { if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() { assert_eq!( @@ -9036,7 +9202,7 @@ async fn test_toggle_comment(cx: &mut gpui::TestAppContext) { } "}); - cx.update_editor(|e, cx| e.toggle_comments(&ToggleComments::default(), cx)); + cx.update_editor(|e, window, cx| e.toggle_comments(&ToggleComments::default(), window, cx)); cx.assert_editor_state(indoc! {" fn a() { @@ -9048,7 +9214,7 @@ async fn test_toggle_comment(cx: &mut gpui::TestAppContext) { // The comment prefix is inserted at the same column for every line in a // selection. - cx.update_editor(|e, cx| e.toggle_comments(&ToggleComments::default(), cx)); + cx.update_editor(|e, window, cx| e.toggle_comments(&ToggleComments::default(), window, cx)); cx.assert_editor_state(indoc! {" fn a() { @@ -9067,7 +9233,7 @@ async fn test_toggle_comment(cx: &mut gpui::TestAppContext) { } "}); - cx.update_editor(|e, cx| e.toggle_comments(&ToggleComments::default(), cx)); + cx.update_editor(|e, window, cx| e.toggle_comments(&ToggleComments::default(), window, cx)); cx.assert_editor_state(indoc! {" fn a() { @@ -9086,7 +9252,7 @@ async fn test_toggle_comment(cx: &mut gpui::TestAppContext) { } "}); - cx.update_editor(|e, cx| e.toggle_comments(&ToggleComments::default(), cx)); + cx.update_editor(|e, window, cx| e.toggle_comments(&ToggleComments::default(), window, cx)); cx.assert_editor_state(indoc! {" fn a() { @@ -9105,7 +9271,7 @@ async fn test_toggle_comment(cx: &mut gpui::TestAppContext) { } "}); - cx.update_editor(|e, cx| e.toggle_comments(&ToggleComments::default(), cx)); + cx.update_editor(|e, window, cx| e.toggle_comments(&ToggleComments::default(), window, cx)); cx.assert_editor_state(indoc! {" fn a() { @@ -9124,7 +9290,7 @@ async fn test_toggle_comment(cx: &mut gpui::TestAppContext) { } "}); - cx.update_editor(|e, cx| e.toggle_comments(&ToggleComments::default(), cx)); + cx.update_editor(|e, window, cx| e.toggle_comments(&ToggleComments::default(), window, cx)); cx.assert_editor_state(indoc! {" fn a() { @@ -9162,7 +9328,7 @@ async fn test_toggle_comment_ignore_indent(cx: &mut gpui::TestAppContext) { } "}); - cx.update_editor(|e, cx| e.toggle_comments(toggle_comments, cx)); + cx.update_editor(|e, window, cx| e.toggle_comments(toggle_comments, window, cx)); cx.assert_editor_state(indoc! {" fn a() { @@ -9173,7 +9339,7 @@ async fn test_toggle_comment_ignore_indent(cx: &mut gpui::TestAppContext) { "}); // The comment prefix is inserted at the beginning of each line - cx.update_editor(|e, cx| e.toggle_comments(toggle_comments, cx)); + cx.update_editor(|e, window, cx| e.toggle_comments(toggle_comments, window, cx)); cx.assert_editor_state(indoc! {" fn a() { @@ -9192,7 +9358,7 @@ async fn test_toggle_comment_ignore_indent(cx: &mut gpui::TestAppContext) { } "}); - cx.update_editor(|e, cx| e.toggle_comments(toggle_comments, cx)); + cx.update_editor(|e, window, cx| e.toggle_comments(toggle_comments, window, cx)); cx.assert_editor_state(indoc! {" fn a() { @@ -9211,7 +9377,7 @@ async fn test_toggle_comment_ignore_indent(cx: &mut gpui::TestAppContext) { } "}); - cx.update_editor(|e, cx| e.toggle_comments(toggle_comments, cx)); + cx.update_editor(|e, window, cx| e.toggle_comments(toggle_comments, window, cx)); cx.assert_editor_state(indoc! {" fn a() { @@ -9230,7 +9396,7 @@ async fn test_toggle_comment_ignore_indent(cx: &mut gpui::TestAppContext) { } "}); - cx.update_editor(|e, cx| e.toggle_comments(toggle_comments, cx)); + cx.update_editor(|e, window, cx| e.toggle_comments(toggle_comments, window, cx)); cx.assert_editor_state(indoc! {" fn a() { @@ -9249,7 +9415,7 @@ async fn test_toggle_comment_ignore_indent(cx: &mut gpui::TestAppContext) { } "}); - cx.update_editor(|e, cx| e.toggle_comments(toggle_comments, cx)); + cx.update_editor(|e, window, cx| e.toggle_comments(toggle_comments, window, cx)); cx.assert_editor_state(indoc! {" fn a() { @@ -9292,8 +9458,8 @@ async fn test_advance_downward_on_toggle_comment(cx: &mut gpui::TestAppContext) cat(); }" )); - cx.update_editor(|editor, cx| { - editor.toggle_comments(toggle_comments, cx); + cx.update_editor(|editor, window, cx| { + editor.toggle_comments(toggle_comments, window, cx); }); cx.assert_editor_state(indoc!( "fn a() { @@ -9309,8 +9475,8 @@ async fn test_advance_downward_on_toggle_comment(cx: &mut gpui::TestAppContext) cat(); }" )); - cx.update_editor(|editor, cx| { - editor.toggle_comments(toggle_comments, cx); + cx.update_editor(|editor, window, cx| { + editor.toggle_comments(toggle_comments, window, cx); }); cx.assert_editor_state(indoc!( "fn a() { @@ -9326,8 +9492,8 @@ async fn test_advance_downward_on_toggle_comment(cx: &mut gpui::TestAppContext) cat(); }" )); - cx.update_editor(|editor, cx| { - editor.toggle_comments(toggle_comments, cx); + cx.update_editor(|editor, window, cx| { + editor.toggle_comments(toggle_comments, window, cx); }); cx.assert_editor_state(indoc!( "fn a() { @@ -9343,8 +9509,8 @@ async fn test_advance_downward_on_toggle_comment(cx: &mut gpui::TestAppContext) cat(); }" )); - cx.update_editor(|editor, cx| { - editor.toggle_comments(toggle_comments, cx); + cx.update_editor(|editor, window, cx| { + editor.toggle_comments(toggle_comments, window, cx); }); cx.assert_editor_state(indoc!( "fn a() { @@ -9362,8 +9528,8 @@ async fn test_advance_downward_on_toggle_comment(cx: &mut gpui::TestAppContext) cat(); }" )); - cx.update_editor(|editor, cx| { - editor.toggle_comments(toggle_comments, cx); + cx.update_editor(|editor, window, cx| { + editor.toggle_comments(toggle_comments, window, cx); }); cx.assert_editor_state(indoc!( "fn a() { @@ -9381,8 +9547,8 @@ async fn test_advance_downward_on_toggle_comment(cx: &mut gpui::TestAppContext) cat(); }" )); - cx.update_editor(|editor, cx| { - editor.toggle_comments(toggle_comments, cx); + cx.update_editor(|editor, window, cx| { + editor.toggle_comments(toggle_comments, window, cx); }); cx.assert_editor_state(indoc!( "fn a() { @@ -9441,7 +9607,9 @@ async fn test_toggle_block_comment(cx: &mut gpui::TestAppContext) { "# .unindent(), ); - cx.update_editor(|editor, cx| editor.toggle_comments(&ToggleComments::default(), cx)); + cx.update_editor(|editor, window, cx| { + editor.toggle_comments(&ToggleComments::default(), window, cx) + }); cx.assert_editor_state( &r#" @@ -9450,7 +9618,9 @@ async fn test_toggle_block_comment(cx: &mut gpui::TestAppContext) { "# .unindent(), ); - cx.update_editor(|editor, cx| editor.toggle_comments(&ToggleComments::default(), cx)); + cx.update_editor(|editor, window, cx| { + editor.toggle_comments(&ToggleComments::default(), window, cx) + }); cx.assert_editor_state( &r#"

A

ˇ @@ -9472,7 +9642,9 @@ async fn test_toggle_block_comment(cx: &mut gpui::TestAppContext) { .unindent(), ); - cx.update_editor(|editor, cx| editor.toggle_comments(&ToggleComments::default(), cx)); + cx.update_editor(|editor, window, cx| { + editor.toggle_comments(&ToggleComments::default(), window, cx) + }); cx.assert_editor_state( &r#" " "$2" + if [ "$dry" = true ]; then + ruplacer "$1" "$2" crates/ --type *.rs + else + ruplacer "$1" "$2" crates/ --type *.rs --go + fi +} + +re '\.new_view\(' '.new_model(' +re 'cx.view\(' 'cx.model(' +re '\.observe_new_views\(' '.observe_new_models(' +re 'View<' 'Model<' +re 'FocusableView' 'Focusable' + +# closure parameters +re ', &mut WindowContext\)' ', &mut Window, &mut AppContext)' +re ', &mut ViewContext<([^>]+)>\)' ', &mut Window, &mut ModelContext<$1>)' +re '\(&mut WindowContext\)' '(&mut Window, &mut AppContext)' +re '\(&mut ViewContext<([^>]+)>\)' '(&mut Window, &mut ModelContext<$1>)' + +# function parameters +re '_: &mut WindowContext\)' '_window: &mut Window, _cx: &mut AppContext)' +re '_: &mut ViewContext<([^>]+)>\)' '_window: &mut Window, _cx: &mut ModelContext<$1>)' +re '_: &mut WindowContext,' '_window: &mut Window, _cx: &mut AppContext,' +re '_: &mut ViewContext<([^>]+)>,' '_window: &mut Window, _cx: &mut ModelContext<$1>,' +re '_cx: &mut WindowContext\)' '_window: &mut Window, _cx: &mut AppContext)' +re '_cx: &mut ViewContext<([^>]+)>\)' '_window: &mut Window, _cx: &mut ModelContext<$1>)' +re '_cx: &mut WindowContext,' '_window: &mut Window, _cx: &mut AppContext,' +re '_cx: &mut ViewContext<([^>]+)>,' '_window: &mut Window, _cx: &mut ModelContext<$1>,' +re 'cx: &mut WindowContext\)' 'window: &mut Window, cx: &mut AppContext)' +re 'cx: &mut ViewContext<([^>]+)>\)' 'window: &mut Window, cx: &mut ModelContext<$1>)' +re 'cx: &mut WindowContext,' 'window: &mut Window, cx: &mut AppContext,' +re 'cx: &mut ViewContext<([^>]+)>,' 'window: &mut Window, cx: &mut ModelContext<$1>,' + +re '_: &WindowContext\)' '_window: &Window, _cx: &AppContext)' +re '_: &ViewContext<([^>]+)>\)' '_window: &Window, _cx: &ModelContext<$1>)' +re '_: &WindowContext,' '_window: &Window, _cx: &AppContext,' +re '_: &ViewContext<([^>]+)>,' '_window: &Window, _cx: &ModelContext<$1>,' +re '_cx: &WindowContext\)' '_window: &Window, _cx: &AppContext)' +re '_cx: &ViewContext<([^>]+)>\)' '_window: &Window, _cx: &ModelContext<$1>)' +re '_cx: &WindowContext,' '_window: &Window, _cx: &AppContext,' +re '_cx: &ViewContext<([^>]+)>,' '_window: &Window, _cx: &ModelContext<$1>,' +re 'cx: &WindowContext\)' 'window: &Window, cx: &AppContext)' +re 'cx: &ViewContext<([^>]+)>\)' 'window: &Window, cx: &ModelContext<$1>)' +re 'cx: &WindowContext,' 'window: &Window, cx: &AppContext,' +re 'cx: &ViewContext<([^>]+)>,' 'window: &Window, cx: &ModelContext<$1>,' + +# VisualContext methods moved to window, that take context +re 'cx.dismiss_view\(' 'window.dismiss_view(cx, ' +re 'cx.focus_view\(' 'window.focus_view(cx, ' +re 'cx.new_view\(' 'window.new_view(cx, ' +re 'cx.replace_root_view\(' 'window.replace_root_view(cx, ' + +# AppContext methods moved to window, that take context +re 'cx.appearance_changed\(\)' 'window.appearance_changed(cx)' +re 'cx.available_actions\(\)' 'window.available_actions(cx)' +re 'cx.dispatch_keystroke_observers\(' 'window.dispatch_keystroke_observers(cx, ' +re 'cx.display\(\)' 'window.display(cx)' +re 'cx.focused\(\)' 'window.focused(cx)' +re 'cx.handle_input\(' 'window.handle_input(cx, ' +re 'cx.paint_svg\(' 'window.paint_svg(cx, ' +re 'cx.request_layout\(' 'window.request_layout(cx, ' +re 'cx.use_asset\(' 'window.use_asset(cx, ' + +# Subset of AppContext methods moved to window that don't take context +re 'cx\.set_cursor_style\(' 'window.set_cursor_style(' +re 'cx\.modifiers\(' 'window.modifiers(' +re 'cx\.mouse_position\(' 'window.mouse_position(' +re 'cx\.text_style\(' 'window.text_style(' +re 'cx\.line_height\(' 'window.line_height(' + +# common closure patterns +re 'cx.listener\(move \|this, _, cx\|' 'cx.listener(move |this, _, window, cx|' +re 'cx.listener\(\|this, _, cx\|' 'cx.listener(|this, _, window, cx|' +re 'cx.listener\(move \|_, _, cx\|' 'cx.listener(move |_, _, window, cx|' +re 'cx.listener\(\|_, _, cx\|' 'cx.listener(|_, _, window, cx|' +re '\.on_click\(move \|_, cx\|' '.on_click(move |_, window, cx|' +re '\.on_mouse_move\(\|_, cx\|' '.on_mouse_move(|_, window, cx|' + +# cleanup imports +re ' ViewContext,' '' +re ' WindowContext,' '' +re ' WeakView,' '' +re ' View,' '' +re ', ViewContext\}' '}' +re ', WindowContext\}' '}' +re ', WeakView\}' '}' +re ', View\}' '}' + +# other patterns +re '\.detach_and_notify_err\(cx' '.detach_and_notify_err(window, cx' diff --git a/resolve-their-hunks.py b/resolve-their-hunks.py new file mode 100755 index 0000000000..2ac3841632 --- /dev/null +++ b/resolve-their-hunks.py @@ -0,0 +1,68 @@ +#!/bin/env python3 + +import os +from pathlib import Path + +def process_file(filepath): + with open(filepath, 'r', encoding='utf-8') as f: + lines = f.readlines() + + modified_lines = [] + in_conflict = False + after_equals = False + keep_lines = [] + + for line in lines: + if line.startswith('<<<<<<<'): + in_conflict = True + after_equals = False + keep_lines = [] + continue + elif line.startswith('======='): + after_equals = True + continue + elif line.startswith('>>>>>>>'): + in_conflict = False + after_equals = False + modified_lines.extend(keep_lines) + continue + + if in_conflict: + if after_equals: + keep_lines.append(line) + else: + modified_lines.append(line) + + # Only write if changes were made + if lines != modified_lines: + with open(filepath, 'w', encoding='utf-8') as f: + f.writelines(modified_lines) + print(f"Processed: {filepath}") + return True + return False + +def main(): + # Get current directory + current_dir = Path('.') + + # Find all .rs files recursively + rust_files = list(current_dir.rglob('*.rs')) + + files_processed = 0 + files_modified = 0 + + # Process each file + for filepath in rust_files: + try: + files_processed += 1 + if process_file(filepath): + files_modified += 1 + except Exception as e: + print(f"Error processing {filepath}: {str(e)}") + + print(f"\nSummary:") + print(f"Files processed: {files_processed}") + print(f"Files modified: {files_modified}") + +if __name__ == "__main__": + main() diff --git a/tooling/xtask/src/tasks/package_conformity.rs b/tooling/xtask/src/tasks/package_conformity.rs index 8a17e7be43..de2db3cdd1 100644 --- a/tooling/xtask/src/tasks/package_conformity.rs +++ b/tooling/xtask/src/tasks/package_conformity.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::fs; use std::path::Path; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, Context as _, Result}; use cargo_toml::{Dependency, Manifest}; use clap::Parser; diff --git a/tooling/xtask/src/workspace.rs b/tooling/xtask/src/workspace.rs index 4c4ece6cff..fd71aa6bbd 100644 --- a/tooling/xtask/src/workspace.rs +++ b/tooling/xtask/src/workspace.rs @@ -1,4 +1,4 @@ -use anyhow::{Context, Result}; +use anyhow::{Context as _, Result}; use cargo_metadata::{Metadata, MetadataCommand}; /// Returns the Cargo workspace.