From 6fca1d2b0ba93cdbc3255657a990828a0f22b199 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 25 Jan 2025 20:02:45 -0700 Subject: [PATCH] Eliminate GPUI View, ViewContext, and WindowContext types (#22632) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's still a bit more work to do on this, but this PR is compiling (with warnings) after eliminating the key types. When the tasks below are complete, this will be the new narrative for GPUI: - `Entity` - This replaces `View`/`Model`. It represents a unit of state, and if `T` implements `Render`, then `Entity` implements `Element`. - `&mut App` This replaces `AppContext` and represents the app. - `&mut Context` This replaces `ModelContext` and derefs to `App`. It is provided by the framework when updating an entity. - `&mut Window` Broken out of `&mut WindowContext` which no longer exists. Every method that once took `&mut WindowContext` now takes `&mut Window, &mut App` and every method that took `&mut ViewContext` now takes `&mut Window, &mut Context` Not pictured here are the two other failed attempts. It's been quite a month! Tasks: - [x] Remove `View`, `ViewContext`, `WindowContext` and thread through `Window` - [x] [@cole-miller @mikayla-maki] Redraw window when entities change - [x] [@cole-miller @mikayla-maki] Get examples and Zed running - [x] [@cole-miller @mikayla-maki] Fix Zed rendering - [x] [@mikayla-maki] Fix todo! macros and comments - [x] Fix a bug where the editor would not be redrawn because of view caching - [x] remove publicness window.notify() and replace with `AppContext::notify` - [x] remove `observe_new_window_models`, replace with `observe_new_models` with an optional window - [x] Fix a bug where the project panel would not be redrawn because of the wrong refresh() call being used - [x] Fix the tests - [x] Fix warnings by eliminating `Window` params or using `_` - [x] Fix conflicts - [x] Simplify generic code where possible - [x] Rename types - [ ] Update docs ### issues post merge - [x] Issues switching between normal and insert mode - [x] Assistant re-rendering failure - [x] Vim test failures - [x] Mac build issue Release Notes: - N/A --------- Co-authored-by: Antonio Scandurra Co-authored-by: Cole Miller Co-authored-by: Mikayla Co-authored-by: Joseph Co-authored-by: max Co-authored-by: Michael Sloan Co-authored-by: Mikayla Maki Co-authored-by: Mikayla Co-authored-by: joão --- .../src/activity_indicator.rs | 125 +- crates/anthropic/src/anthropic.rs | 2 +- crates/assets/src/assets.rs | 6 +- crates/assistant/src/assistant.rs | 14 +- .../assistant/src/assistant_configuration.rs | 42 +- crates/assistant/src/assistant_panel.rs | 481 ++- crates/assistant/src/inline_assistant.rs | 780 ++-- .../assistant/src/slash_command_settings.rs | 4 +- .../src/terminal_inline_assistant.rs | 297 +- crates/assistant2/src/active_thread.rs | 67 +- crates/assistant2/src/assistant.rs | 6 +- .../assistant2/src/assistant_configuration.rs | 36 +- .../src/assistant_model_selector.rs | 22 +- crates/assistant2/src/assistant_panel.rs | 328 +- crates/assistant2/src/buffer_codegen.rs | 126 +- crates/assistant2/src/context.rs | 18 +- crates/assistant2/src/context_picker.rs | 111 +- .../directory_context_picker.rs | 66 +- .../context_picker/fetch_context_picker.rs | 67 +- .../src/context_picker/file_context_picker.rs | 111 +- .../context_picker/thread_context_picker.rs | 68 +- crates/assistant2/src/context_store.rs | 121 +- crates/assistant2/src/context_strip.rs | 137 +- crates/assistant2/src/inline_assistant.rs | 468 ++- crates/assistant2/src/inline_prompt_editor.rs | 301 +- crates/assistant2/src/message_editor.rs | 160 +- crates/assistant2/src/terminal_codegen.rs | 24 +- .../src/terminal_inline_assistant.rs | 109 +- crates/assistant2/src/thread.rs | 20 +- crates/assistant2/src/thread_history.rs | 82 +- crates/assistant2/src/thread_store.rs | 46 +- crates/assistant2/src/ui/context_pill.rs | 26 +- .../src/assistant_context_editor.rs | 4 +- .../assistant_context_editor/src/context.rs | 146 +- .../src/context/context_tests.rs | 84 +- .../src/context_editor.rs | 769 ++-- .../src/context_history.rs | 73 +- .../src/context_store.rs | 104 +- crates/assistant_context_editor/src/patch.rs | 38 +- .../src/slash_command.rs | 90 +- .../src/slash_command_picker.rs | 57 +- .../src/assistant_settings.rs | 6 +- .../src/assistant_slash_command.rs | 17 +- .../src/extension_slash_command.rs | 14 +- .../src/slash_command_registry.rs | 6 +- .../src/slash_command_working_set.rs | 8 +- .../src/assistant_slash_commands.rs | 8 +- .../src/auto_command.rs | 18 +- .../src/cargo_workspace_command.rs | 16 +- .../src/context_server_command.rs | 18 +- .../src/default_command.rs | 12 +- .../src/delta_command.rs | 13 +- .../src/diagnostics_command.rs | 24 +- .../src/docs_command.rs | 18 +- .../src/fetch_command.rs | 12 +- .../src/file_command.rs | 20 +- .../src/now_command.rs | 12 +- .../src/project_command.rs | 16 +- .../src/prompt_command.rs | 14 +- .../src/search_command.rs | 16 +- .../src/selection_command.rs | 17 +- .../src/streaming_example_command.rs | 12 +- .../src/symbols_command.rs | 14 +- .../src/tab_command.rs | 30 +- .../src/terminal_command.rs | 20 +- crates/assistant_tool/src/assistant_tool.rs | 9 +- crates/assistant_tool/src/tool_registry.rs | 6 +- crates/assistant_tool/src/tool_working_set.rs | 6 +- crates/assistant_tools/src/assistant_tools.rs | 4 +- crates/assistant_tools/src/now_tool.rs | 7 +- crates/audio/src/assets.rs | 6 +- crates/audio/src/audio.rs | 8 +- crates/auto_update/src/auto_update.rs | 53 +- crates/auto_update_ui/src/auto_update_ui.rs | 55 +- .../auto_update_ui/src/update_notification.rs | 22 +- crates/breadcrumbs/src/breadcrumbs.rs | 31 +- crates/call/src/call_settings.rs | 4 +- crates/call/src/cross_platform/mod.rs | 72 +- crates/call/src/cross_platform/participant.rs | 4 +- crates/call/src/cross_platform/room.rs | 114 +- crates/call/src/macos/mod.rs | 72 +- crates/call/src/macos/participant.rs | 4 +- crates/call/src/macos/room.rs | 112 +- crates/channel/src/channel.rs | 4 +- crates/channel/src/channel_buffer.rs | 48 +- crates/channel/src/channel_chat.rs | 56 +- crates/channel/src/channel_store.rs | 87 +- crates/channel/src/channel_store_tests.rs | 18 +- crates/cli/src/main.rs | 4 +- crates/client/src/client.rs | 52 +- crates/client/src/telemetry.rs | 6 +- crates/client/src/test.rs | 6 +- crates/client/src/user.rs | 55 +- crates/client/src/zed_urls.rs | 6 +- crates/collab/src/auth.rs | 2 +- crates/collab/src/main.rs | 1 + crates/collab/src/seed.rs | 2 +- crates/collab/src/stripe_billing.rs | 2 +- crates/collab/src/tests.rs | 6 +- .../collab/src/tests/channel_buffer_tests.rs | 75 +- .../collab/src/tests/channel_guest_tests.rs | 4 +- .../collab/src/tests/channel_message_tests.rs | 24 +- crates/collab/src/tests/channel_tests.rs | 8 +- crates/collab/src/tests/editor_tests.rs | 284 +- crates/collab/src/tests/following_tests.rs | 408 +- crates/collab/src/tests/integration_tests.rs | 53 +- crates/collab/src/tests/notification_tests.rs | 4 +- .../random_project_collaboration_tests.rs | 18 +- .../remote_editing_collaboration_tests.rs | 10 +- crates/collab/src/tests/test_server.rs | 94 +- crates/collab/src/user_backfiller.rs | 2 +- crates/collab_ui/src/channel_view.rs | 275 +- crates/collab_ui/src/chat_panel.rs | 227 +- .../src/chat_panel/message_editor.rs | 80 +- crates/collab_ui/src/collab_panel.rs | 892 +++-- .../src/collab_panel/channel_modal.rs | 185 +- .../src/collab_panel/contact_finder.rs | 51 +- crates/collab_ui/src/collab_ui.rs | 6 +- crates/collab_ui/src/notification_panel.rs | 222 +- crates/collab_ui/src/notifications.rs | 4 +- .../src/notifications/collab_notification.rs | 2 +- .../incoming_call_notification.rs | 24 +- .../project_shared_notification.rs | 34 +- .../stories/collab_notification.rs | 2 +- crates/collab_ui/src/panel_settings.rs | 8 +- crates/command_palette/src/command_palette.rs | 146 +- .../src/command_palette_hooks.rs | 28 +- crates/context_server/src/client.rs | 2 +- crates/context_server/src/context_server.rs | 4 +- .../context_server/src/context_server_tool.rs | 11 +- .../src/extension_context_server.rs | 13 +- crates/context_server/src/manager.rs | 18 +- crates/context_server/src/registry.rs | 15 +- .../src/context_server_settings.rs | 6 +- crates/copilot/src/copilot.rs | 91 +- crates/copilot/src/copilot_chat.rs | 12 +- .../src/copilot_completion_provider.rs | 200 +- crates/copilot/src/sign_in.rs | 62 +- crates/db/src/db.rs | 6 +- crates/diagnostics/src/diagnostics.rs | 276 +- crates/diagnostics/src/diagnostics_tests.rs | 154 +- crates/diagnostics/src/items.rs | 74 +- .../src/project_diagnostics_settings.rs | 4 +- crates/diagnostics/src/toolbar_controls.rs | 23 +- crates/docs_preprocessor/src/main.rs | 2 +- crates/editor/src/blame_entry_tooltip.rs | 35 +- crates/editor/src/blink_manager.rs | 16 +- crates/editor/src/clangd_ext.rs | 15 +- crates/editor/src/code_context_menus.rs | 101 +- crates/editor/src/display_map.rs | 141 +- crates/editor/src/display_map/block_map.rs | 41 +- crates/editor/src/display_map/crease_map.rs | 50 +- crates/editor/src/display_map/fold_map.rs | 28 +- crates/editor/src/display_map/inlay_map.rs | 10 +- crates/editor/src/display_map/tab_map.rs | 10 +- crates/editor/src/display_map/wrap_map.rs | 22 +- crates/editor/src/editor.rs | 3182 +++++++++------ crates/editor/src/editor_settings.rs | 9 +- crates/editor/src/editor_settings_controls.rs | 78 +- crates/editor/src/editor_tests.rs | 3414 +++++++++-------- crates/editor/src/element.rs | 1898 +++++---- crates/editor/src/git/blame.rs | 41 +- crates/editor/src/git/project_diff.rs | 194 +- .../editor/src/highlight_matching_bracket.rs | 13 +- crates/editor/src/hover_links.rs | 120 +- crates/editor/src/hover_popover.rs | 222 +- crates/editor/src/hunk_diff.rs | 1586 ++++++++ crates/editor/src/indent_guides.rs | 29 +- crates/editor/src/inlay_hint_cache.rs | 263 +- crates/editor/src/inline_completion_tests.rs | 68 +- crates/editor/src/items.rs | 308 +- crates/editor/src/linked_editing_ranges.rs | 10 +- crates/editor/src/lsp_ext.rs | 6 +- crates/editor/src/mouse_context_menu.rs | 81 +- crates/editor/src/movement.rs | 47 +- crates/editor/src/proposed_changes_editor.rs | 153 +- crates/editor/src/rust_analyzer_ext.rs | 31 +- crates/editor/src/scroll.rs | 123 +- crates/editor/src/scroll/actions.rs | 68 +- crates/editor/src/scroll/autoscroll.rs | 27 +- crates/editor/src/selections_collection.rs | 57 +- crates/editor/src/signature_help.rs | 23 +- crates/editor/src/signature_help/popover.rs | 12 +- crates/editor/src/tasks.rs | 15 +- crates/editor/src/test.rs | 36 +- .../src/test/editor_lsp_test_context.rs | 30 +- crates/editor/src/test/editor_test_context.rs | 104 +- crates/evals/src/eval.rs | 14 +- crates/extension/src/extension.rs | 4 +- crates/extension/src/extension_host_proxy.rs | 14 +- crates/extension/src/extension_manifest.rs | 2 +- crates/extension_host/src/extension_host.rs | 72 +- .../extension_host/src/extension_settings.rs | 4 +- .../src/extension_store_test.rs | 8 +- crates/extension_host/src/headless_host.rs | 20 +- crates/extension_host/src/wasm_host.rs | 4 +- crates/extension_host/src/wasm_host/wit.rs | 2 +- .../src/components/extension_card.rs | 2 +- .../src/components/feature_upsell.rs | 4 +- crates/extensions_ui/src/extension_suggest.rs | 21 +- .../src/extension_version_selector.rs | 55 +- crates/extensions_ui/src/extensions_ui.rs | 237 +- crates/feature_flags/src/feature_flags.rs | 30 +- crates/feedback/src/feedback.rs | 42 +- crates/feedback/src/feedback_modal.rs | 110 +- crates/feedback/src/system_specs.rs | 6 +- crates/file_finder/src/file_finder.rs | 276 +- .../file_finder/src/file_finder_settings.rs | 2 +- crates/file_finder/src/file_finder_tests.rs | 205 +- crates/file_finder/src/new_path_prompt.rs | 79 +- crates/file_finder/src/open_path_prompt.rs | 42 +- crates/file_icons/src/file_icons.rs | 16 +- crates/fs/src/fs.rs | 8 +- crates/git/src/blame.rs | 2 +- crates/git/src/git.rs | 2 +- crates/git/src/hosting_provider.rs | 10 +- crates/git/src/repository.rs | 2 +- .../src/git_hosting_providers.rs | 4 +- crates/git_ui/src/git_panel.rs | 376 +- crates/git_ui/src/git_panel_settings.rs | 2 +- crates/git_ui/src/git_ui.rs | 8 +- crates/git_ui/src/repository_selector.rs | 85 +- crates/go_to_line/src/cursor_position.rs | 53 +- crates/go_to_line/src/go_to_line.rs | 161 +- crates/gpui/docs/contexts.md | 2 +- crates/gpui/docs/key_dispatch.md | 8 +- crates/gpui/examples/animation.rs | 14 +- crates/gpui/examples/gif_viewer.rs | 8 +- crates/gpui/examples/gradient.rs | 18 +- crates/gpui/examples/hello_world.rs | 10 +- crates/gpui/examples/image/image.rs | 18 +- crates/gpui/examples/image_loading.rs | 38 +- crates/gpui/examples/input.rs | 165 +- crates/gpui/examples/opacity.rs | 20 +- crates/gpui/examples/ownership_post.rs | 8 +- crates/gpui/examples/painting.rs | 28 +- crates/gpui/examples/set_menus.rs | 14 +- crates/gpui/examples/shadow.rs | 10 +- crates/gpui/examples/svg/svg.rs | 12 +- crates/gpui/examples/text_wrapper.rs | 9 +- crates/gpui/examples/uniform_list.rs | 47 +- crates/gpui/examples/window.rs | 65 +- crates/gpui/examples/window_positioning.rs | 46 +- crates/gpui/examples/window_shadow.rs | 60 +- crates/gpui/src/app.rs | 486 ++- crates/gpui/src/app/async_context.rs | 164 +- crates/gpui/src/app/entity_map.rs | 286 +- crates/gpui/src/app/model_context.rs | 567 ++- crates/gpui/src/app/test_context.rs | 263 +- crates/gpui/src/asset_cache.rs | 6 +- crates/gpui/src/element.rs | 178 +- crates/gpui/src/elements/anchored.rs | 27 +- crates/gpui/src/elements/animation.rs | 21 +- crates/gpui/src/elements/canvas.rs | 29 +- crates/gpui/src/elements/deferred.rs | 17 +- crates/gpui/src/elements/div.rs | 867 +++-- crates/gpui/src/elements/img.rs | 114 +- crates/gpui/src/elements/list.rs | 123 +- crates/gpui/src/elements/surface.rs | 17 +- crates/gpui/src/elements/svg.rs | 48 +- crates/gpui/src/elements/text.rs | 183 +- crates/gpui/src/elements/uniform_list.rs | 122 +- crates/gpui/src/executor.rs | 4 +- crates/gpui/src/geometry.rs | 6 +- crates/gpui/src/global.rs | 6 +- crates/gpui/src/gpui.rs | 82 +- crates/gpui/src/input.rs | 70 +- crates/gpui/src/interactive.rs | 32 +- crates/gpui/src/key_dispatch.rs | 18 +- crates/gpui/src/platform.rs | 71 +- crates/gpui/src/platform/app_menu.rs | 4 +- crates/gpui/src/platform/linux/text_system.rs | 2 +- crates/gpui/src/platform/linux/x11/window.rs | 2 +- .../gpui/src/platform/windows/dispatcher.rs | 2 +- crates/gpui/src/platform/windows/events.rs | 2 +- crates/gpui/src/platform/windows/platform.rs | 2 +- crates/gpui/src/platform/windows/window.rs | 2 +- crates/gpui/src/prelude.rs | 2 +- crates/gpui/src/style.rs | 41 +- crates/gpui/src/taffy.rs | 16 +- crates/gpui/src/test.rs | 2 +- crates/gpui/src/text_system/line.rs | 42 +- crates/gpui/src/view.rs | 389 +- crates/gpui/src/window.rs | 2844 +++++--------- crates/gpui/src/window/prompts.rs | 73 +- crates/gpui_macros/src/derive_render.rs | 2 +- crates/gpui_macros/src/test.rs | 2 +- .../html_to_markdown/src/html_to_markdown.rs | 2 +- crates/image_viewer/src/image_viewer.rs | 91 +- .../src/extension_indexed_docs_provider.rs | 4 +- crates/indexed_docs/src/indexed_docs.rs | 4 +- crates/indexed_docs/src/registry.rs | 6 +- crates/indexed_docs/src/store.rs | 4 +- .../src/inline_completion.rs | 74 +- .../src/inline_completion_button.rs | 280 +- crates/journal/src/journal.rs | 103 +- crates/language/src/buffer.rs | 174 +- crates/language/src/buffer_tests.rs | 190 +- crates/language/src/language.rs | 10 +- crates/language/src/language_registry.rs | 6 +- crates/language/src/language_settings.rs | 16 +- .../src/syntax_map/syntax_map_tests.rs | 50 +- crates/language/src/task_context.rs | 6 +- .../src/extension_lsp_adapter.rs | 2 +- crates/language_model/src/fake_provider.rs | 20 +- crates/language_model/src/language_model.rs | 30 +- crates/language_model/src/registry.rs | 38 +- crates/language_model/src/request.rs | 4 +- .../src/language_model_selector.rs | 91 +- crates/language_models/src/language_models.rs | 13 +- crates/language_models/src/logging.rs | 2 +- .../language_models/src/provider/anthropic.rs | 70 +- crates/language_models/src/provider/cloud.rs | 78 +- .../src/provider/copilot_chat.rs | 38 +- crates/language_models/src/provider/google.rs | 68 +- .../language_models/src/provider/lmstudio.rs | 54 +- crates/language_models/src/provider/ollama.rs | 55 +- .../language_models/src/provider/open_ai.rs | 70 +- crates/language_models/src/settings.rs | 6 +- .../src/active_buffer_language.rs | 26 +- .../src/language_selector.rs | 92 +- crates/language_tools/src/key_context_view.rs | 75 +- crates/language_tools/src/language_tools.rs | 4 +- crates/language_tools/src/lsp_log.rs | 668 ++-- crates/language_tools/src/lsp_log_tests.rs | 7 +- crates/language_tools/src/syntax_tree_view.rs | 143 +- crates/languages/src/c.rs | 4 +- crates/languages/src/css.rs | 5 +- crates/languages/src/go.rs | 8 +- crates/languages/src/json.rs | 4 +- crates/languages/src/lib.rs | 6 +- crates/languages/src/python.rs | 14 +- crates/languages/src/rust.rs | 12 +- crates/languages/src/typescript.rs | 5 +- crates/livekit_client/examples/test_app.rs | 51 +- .../src/remote_video_track_view.rs | 23 +- crates/livekit_client/src/test.rs | 2 +- .../examples/test_app_macos.rs | 4 +- crates/livekit_client_macos/src/prod.rs | 2 +- crates/livekit_client_macos/src/test.rs | 2 +- crates/lmstudio/src/lmstudio.rs | 2 +- crates/lsp/src/lsp.rs | 8 +- crates/markdown/examples/markdown.rs | 20 +- crates/markdown/examples/markdown_as_child.rs | 23 +- crates/markdown/src/markdown.rs | 180 +- .../markdown_preview/src/markdown_preview.rs | 11 +- .../src/markdown_preview_view.rs | 194 +- .../markdown_preview/src/markdown_renderer.rs | 75 +- crates/multi_buffer/src/multi_buffer.rs | 246 +- crates/multi_buffer/src/multi_buffer_tests.rs | 175 +- .../notifications/src/notification_store.rs | 42 +- crates/ollama/src/ollama.rs | 2 +- crates/open_ai/src/open_ai.rs | 2 +- crates/outline/src/outline.rs | 143 +- crates/outline_panel/src/outline_panel.rs | 1144 +++--- .../src/outline_panel_settings.rs | 2 +- crates/picker/src/head.rs | 36 +- .../src/highlighted_match_with_paths.rs | 4 +- crates/picker/src/picker.rs | 341 +- crates/prettier/src/prettier.rs | 6 +- crates/project/src/buffer_store.rs | 287 +- crates/project/src/connection_manager.rs | 22 +- crates/project/src/debounced_delay.rs | 6 +- crates/project/src/environment.rs | 16 +- crates/project/src/git.rs | 29 +- crates/project/src/image_store.rs | 121 +- crates/project/src/lsp_command.rs | 278 +- crates/project/src/lsp_ext_command.rs | 52 +- crates/project/src/lsp_store.rs | 409 +- crates/project/src/prettier_store.rs | 42 +- crates/project/src/project.rs | 692 ++-- crates/project/src/project_settings.rs | 43 +- crates/project/src/project_tests.rs | 13 +- crates/project/src/search.rs | 14 +- crates/project/src/task_inventory.rs | 32 +- crates/project/src/task_store.rs | 57 +- crates/project/src/terminals.rs | 36 +- crates/project/src/toolchain_store.rs | 55 +- crates/project/src/worktree_store.rs | 98 +- crates/project/src/yarn.rs | 8 +- crates/project_panel/src/project_panel.rs | 1520 ++++---- .../src/project_panel_settings.rs | 2 +- crates/project_symbols/src/project_symbols.rs | 109 +- crates/prompt_library/src/prompt_library.rs | 446 ++- crates/prompt_library/src/prompt_store.rs | 6 +- crates/prompt_library/src/prompts.rs | 6 +- .../src/disconnected_overlay.rs | 103 +- crates/recent_projects/src/recent_projects.rs | 189 +- crates/recent_projects/src/remote_servers.rs | 418 +- crates/recent_projects/src/ssh_connections.rs | 116 +- crates/release_channel/src/lib.rs | 14 +- crates/remote/src/ssh_session.rs | 56 +- crates/remote_server/src/headless_project.rs | 62 +- .../remote_server/src/remote_editing_tests.rs | 12 +- crates/remote_server/src/unix.rs | 22 +- .../repl/src/components/kernel_list_item.rs | 2 +- crates/repl/src/components/kernel_options.rs | 38 +- crates/repl/src/jupyter_settings.rs | 6 +- crates/repl/src/kernels/mod.rs | 10 +- crates/repl/src/kernels/native_kernel.rs | 19 +- crates/repl/src/kernels/remote_kernels.rs | 17 +- crates/repl/src/notebook/cell.rs | 119 +- crates/repl/src/notebook/notebook_ui.rs | 308 +- crates/repl/src/outputs.rs | 168 +- crates/repl/src/outputs/image.rs | 10 +- crates/repl/src/outputs/markdown.rs | 18 +- crates/repl/src/outputs/plain.rs | 65 +- crates/repl/src/outputs/table.rs | 29 +- crates/repl/src/outputs/user_error.rs | 8 +- crates/repl/src/repl.rs | 6 +- crates/repl/src/repl_editor.rs | 88 +- crates/repl/src/repl_sessions_ui.rs | 177 +- crates/repl/src/repl_store.rs | 40 +- crates/repl/src/session.rs | 118 +- crates/reqwest_client/examples/client.rs | 2 +- crates/rich_text/src/rich_text.rs | 18 +- crates/rpc/src/auth.rs | 2 +- crates/rpc/src/peer.rs | 2 +- crates/rpc/src/proto_client.rs | 18 +- crates/search/src/buffer_search.rs | 1011 ++--- crates/search/src/buffer_search/registrar.rs | 41 +- crates/search/src/project_search.rs | 1319 ++++--- crates/search/src/search.rs | 16 +- crates/search/src/search_bar.rs | 4 +- crates/semantic_index/examples/index.rs | 4 +- crates/semantic_index/src/embedding/cloud.rs | 2 +- crates/semantic_index/src/embedding_index.rs | 31 +- crates/semantic_index/src/project_index.rs | 40 +- .../src/project_index_debug_view.rs | 91 +- crates/semantic_index/src/semantic_index.rs | 31 +- crates/semantic_index/src/summary_index.rs | 30 +- crates/semantic_index/src/worktree_index.rs | 26 +- crates/session/src/session.rs | 6 +- .../settings/src/editable_setting_control.rs | 8 +- crates/settings/src/keymap_file.rs | 16 +- crates/settings/src/settings.rs | 4 +- crates/settings/src/settings_file.rs | 12 +- crates/settings/src/settings_store.rs | 76 +- .../src/appearance_settings_controls.rs | 70 +- crates/settings_ui/src/settings_ui.rs | 55 +- crates/snippet/src/snippet.rs | 2 +- .../snippet_provider/src/extension_snippet.rs | 4 +- crates/snippet_provider/src/lib.rs | 28 +- crates/snippet_provider/src/registry.rs | 8 +- crates/snippets_ui/src/snippets_ui.rs | 79 +- crates/sqlez/src/bindable.rs | 2 +- crates/sqlez/src/migrations.rs | 2 +- crates/sqlez/src/thread_safe_connection.rs | 2 +- crates/sqlez/src/typed_statements.rs | 2 +- crates/story/src/story.rs | 8 +- .../src/stories/auto_height_editor.rs | 16 +- crates/storybook/src/stories/cursor.rs | 2 +- .../storybook/src/stories/default_colors.rs | 10 +- crates/storybook/src/stories/focus.rs | 44 +- crates/storybook/src/stories/indent_guides.rs | 11 +- crates/storybook/src/stories/kitchen_sink.rs | 10 +- .../storybook/src/stories/overflow_scroll.rs | 2 +- crates/storybook/src/stories/picker.rs | 36 +- crates/storybook/src/stories/scroll.rs | 12 +- crates/storybook/src/stories/text.rs | 16 +- .../storybook/src/stories/viewport_units.rs | 10 +- crates/storybook/src/stories/with_rem_size.rs | 4 +- crates/storybook/src/story_selector.rs | 68 +- crates/storybook/src/storybook.rs | 21 +- crates/supermaven/src/supermaven.rs | 28 +- .../src/supermaven_completion_provider.rs | 24 +- crates/supermaven_api/src/supermaven_api.rs | 2 +- crates/tab_switcher/src/tab_switcher.rs | 146 +- crates/tab_switcher/src/tab_switcher_tests.rs | 37 +- crates/task/src/static_source.rs | 6 +- crates/tasks_ui/Cargo.toml | 3 + crates/tasks_ui/src/modal.rs | 212 +- crates/tasks_ui/src/settings.rs | 5 +- crates/tasks_ui/src/{lib.rs => tasks_ui.rs} | 92 +- crates/terminal/src/terminal.rs | 37 +- crates/terminal/src/terminal_settings.rs | 9 +- crates/terminal_view/src/persistence.rs | 77 +- crates/terminal_view/src/terminal_element.rs | 199 +- crates/terminal_view/src/terminal_panel.rs | 515 +-- .../terminal_view/src/terminal_tab_tooltip.rs | 8 +- crates/terminal_view/src/terminal_view.rs | 421 +- crates/theme/src/font_family_cache.rs | 8 +- crates/theme/src/registry.rs | 10 +- crates/theme/src/scale.rs | 6 +- crates/theme/src/settings.rs | 23 +- crates/theme/src/styles/colors.rs | 4 +- crates/theme/src/theme.rs | 8 +- crates/theme_extension/src/theme_extension.rs | 4 +- crates/theme_importer/src/main.rs | 2 +- crates/theme_selector/src/theme_selector.rs | 81 +- crates/title_bar/src/application_menu.rs | 48 +- crates/title_bar/src/collab.rs | 116 +- .../title_bar/src/platforms/platform_linux.rs | 6 +- .../src/platforms/platform_windows.rs | 8 +- .../title_bar/src/stories/application_menu.rs | 10 +- crates/title_bar/src/title_bar.rs | 261 +- crates/title_bar/src/window_controls.rs | 21 +- .../src/active_toolchain.rs | 60 +- .../src/toolchain_selector.rs | 108 +- crates/ui/src/components/avatar/avatar.rs | 4 +- .../avatar/avatar_audio_status_indicator.rs | 10 +- .../avatar/avatar_availability_indicator.rs | 4 +- crates/ui/src/components/button/button.rs | 12 +- .../ui/src/components/button/button_icon.rs | 2 +- .../ui/src/components/button/button_like.rs | 37 +- .../ui/src/components/button/icon_button.rs | 8 +- .../ui/src/components/button/toggle_button.rs | 6 +- crates/ui/src/components/content_group.rs | 4 +- crates/ui/src/components/context_menu.rs | 146 +- crates/ui/src/components/disclosure.rs | 10 +- crates/ui/src/components/divider.rs | 8 +- crates/ui/src/components/dropdown_menu.rs | 22 +- crates/ui/src/components/facepile.rs | 4 +- crates/ui/src/components/icon.rs | 16 +- .../ui/src/components/icon/decorated_icon.rs | 4 +- .../ui/src/components/icon/icon_decoration.rs | 6 +- crates/ui/src/components/image.rs | 6 +- crates/ui/src/components/indent_guides.rs | 85 +- crates/ui/src/components/indicator.rs | 4 +- crates/ui/src/components/keybinding.rs | 28 +- .../src/components/label/highlighted_label.rs | 4 +- crates/ui/src/components/label/label.rs | 4 +- crates/ui/src/components/label/label_like.rs | 9 +- crates/ui/src/components/list/list.rs | 2 +- crates/ui/src/components/list/list_header.rs | 10 +- crates/ui/src/components/list/list_item.rs | 25 +- .../ui/src/components/list/list_separator.rs | 2 +- .../ui/src/components/list/list_sub_header.rs | 2 +- crates/ui/src/components/modal.rs | 20 +- crates/ui/src/components/navigable.rs | 27 +- crates/ui/src/components/numeric_stepper.rs | 16 +- crates/ui/src/components/popover.rs | 4 +- crates/ui/src/components/popover_menu.rs | 130 +- crates/ui/src/components/radio.rs | 10 +- crates/ui/src/components/right_click_menu.rs | 247 +- crates/ui/src/components/scrollbar.rs | 48 +- .../ui/src/components/settings_container.rs | 2 +- crates/ui/src/components/settings_group.rs | 2 +- crates/ui/src/components/stories/avatar.rs | 2 +- crates/ui/src/components/stories/button.rs | 2 +- .../ui/src/components/stories/context_menu.rs | 32 +- .../ui/src/components/stories/disclosure.rs | 2 +- crates/ui/src/components/stories/icon.rs | 2 +- .../ui/src/components/stories/icon_button.rs | 18 +- .../ui/src/components/stories/keybinding.rs | 2 +- crates/ui/src/components/stories/label.rs | 2 +- crates/ui/src/components/stories/list.rs | 2 +- .../ui/src/components/stories/list_header.rs | 2 +- crates/ui/src/components/stories/list_item.rs | 16 +- crates/ui/src/components/stories/tab.rs | 2 +- crates/ui/src/components/stories/tab_bar.rs | 2 +- .../src/components/stories/toggle_button.rs | 2 +- .../ui/src/components/stories/tool_strip.rs | 8 +- crates/ui/src/components/tab.rs | 6 +- crates/ui/src/components/tab_bar.rs | 2 +- crates/ui/src/components/table.rs | 6 +- crates/ui/src/components/toggle.rs | 62 +- crates/ui/src/components/tool_strip.rs | 2 +- crates/ui/src/components/tooltip.rs | 65 +- crates/ui/src/prelude.rs | 5 +- crates/ui/src/styles/appearance.rs | 6 +- crates/ui/src/styles/color.rs | 4 +- crates/ui/src/styles/elevation.rs | 8 +- crates/ui/src/styles/spacing.rs | 4 +- crates/ui/src/styles/typography.rs | 23 +- crates/ui/src/styles/units.rs | 10 +- crates/ui/src/traits/clickable.rs | 4 +- crates/ui/src/traits/component_preview.rs | 19 +- crates/ui/src/traits/styled_ext.rs | 22 +- crates/ui/src/utils.rs | 4 +- crates/ui/src/utils/with_rem_size.rs | 26 +- crates/ui_input/src/ui_input.rs | 27 +- crates/ui_macros/src/dynamic_spacing.rs | 6 +- crates/vcs_menu/src/lib.rs | 95 +- crates/vim/src/change_list.rs | 27 +- crates/vim/src/command.rs | 236 +- crates/vim/src/digraph.rs | 75 +- crates/vim/src/helix.rs | 68 +- crates/vim/src/indent.rs | 82 +- crates/vim/src/insert.rs | 34 +- crates/vim/src/mode_indicator.rs | 36 +- crates/vim/src/motion.rs | 237 +- crates/vim/src/normal.rs | 265 +- crates/vim/src/normal/case.rs | 80 +- crates/vim/src/normal/change.rs | 43 +- crates/vim/src/normal/delete.rs | 39 +- crates/vim/src/normal/increment.rs | 30 +- crates/vim/src/normal/mark.rs | 46 +- crates/vim/src/normal/paste.rs | 16 +- crates/vim/src/normal/repeat.rs | 110 +- crates/vim/src/normal/scroll.rs | 92 +- crates/vim/src/normal/search.rs | 180 +- crates/vim/src/normal/substitute.rs | 29 +- crates/vim/src/normal/toggle_comments.rs | 30 +- crates/vim/src/normal/yank.rs | 42 +- crates/vim/src/object.rs | 91 +- crates/vim/src/replace.rs | 42 +- crates/vim/src/rewrap.rs | 41 +- crates/vim/src/state.rs | 22 +- crates/vim/src/surrounds.rs | 53 +- crates/vim/src/test.rs | 50 +- .../src/test/neovim_backed_test_context.rs | 14 +- crates/vim/src/test/vim_test_context.rs | 49 +- crates/vim/src/vim.rs | 403 +- crates/vim/src/visual.rs | 249 +- .../vim_mode_setting/src/vim_mode_setting.rs | 6 +- crates/welcome/src/base_keymap_picker.rs | 63 +- crates/welcome/src/base_keymap_setting.rs | 2 +- crates/welcome/src/multibuffer_hint.rs | 26 +- crates/welcome/src/welcome.rs | 124 +- crates/workspace/src/dock.rs | 452 ++- crates/workspace/src/item.rs | 654 ++-- crates/workspace/src/modal_layer.rs | 68 +- crates/workspace/src/notifications.rs | 183 +- crates/workspace/src/pane.rs | 1285 ++++--- crates/workspace/src/pane_group.rs | 170 +- crates/workspace/src/persistence/model.rs | 39 +- crates/workspace/src/searchable.rs | 208 +- .../src/shared_screen/cross_platform.rs | 41 +- crates/workspace/src/shared_screen/macos.rs | 38 +- crates/workspace/src/status_bar.rs | 79 +- crates/workspace/src/tasks.rs | 6 +- crates/workspace/src/theme_preview.rs | 131 +- crates/workspace/src/toolbar.rs | 54 +- crates/workspace/src/workspace.rs | 2836 ++++++++------ crates/workspace/src/workspace_settings.rs | 6 +- crates/worktree/src/worktree.rs | 123 +- crates/worktree/src/worktree_settings.rs | 9 +- crates/worktree/src/worktree_tests.rs | 8 +- crates/zed/RELEASE_CHANNEL | 2 +- crates/zed/src/main.rs | 80 +- crates/zed/src/reliability.rs | 12 +- crates/zed/src/zed.rs | 939 +++-- .../zed/src/zed/inline_completion_registry.rs | 93 +- crates/zed/src/zed/linux_prompts.rs | 49 +- crates/zed/src/zed/open_listener.rs | 32 +- crates/zed/src/zed/quick_action_bar.rs | 80 +- .../zed/quick_action_bar/markdown_preview.rs | 17 +- .../zed/src/zed/quick_action_bar/repl_menu.rs | 78 +- crates/zed_actions/src/lib.rs | 4 +- crates/zed_predict_tos/src/zed_predict_tos.rs | 47 +- crates/zeta/src/completion_diff_element.rs | 25 +- crates/zeta/src/rate_completion_modal.rs | 148 +- crates/zeta/src/zeta.rs | 90 +- refactor.sh | 111 + resolve-their-hunks.py | 68 + tooling/xtask/src/tasks/package_conformity.rs | 2 +- tooling/xtask/src/workspace.rs | 2 +- 648 files changed, 36251 insertions(+), 28211 deletions(-) create mode 100644 crates/editor/src/hunk_diff.rs rename crates/tasks_ui/src/{lib.rs => tasks_ui.rs} (86%) create mode 100755 refactor.sh create mode 100755 resolve-their-hunks.py diff --git a/crates/activity_indicator/src/activity_indicator.rs b/crates/activity_indicator/src/activity_indicator.rs index 973f845c177669..8c6f5aa176c063 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 1e0fdac11c1c89..28e306d3141493 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 ee990085f6de17..8f8831269bed0d 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 7d291e0643da93..7817c958b395c8 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 e4756e1e860587..fdff8977529cac 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 e5c3c76180fe53..bcd55b7a26bfe9 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 3e6d837e4077db..94dd220f172dfa 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 5918769d711c3f..25d575ed534b37 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 ee48e7ea0e536d..6f2bb6fdba6eb3 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 3f643fdc00ca81..3cade8f003ea4e 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 fdea222fc857b3..0d1303ea90d51f 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 e44fa1833f956e..efecfe729ae48a 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 c31b6bcba38cc0..c71e70d459b478 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 ad648bd54e31c5..07593e8d75e178 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 09850ea5f76978..6c3e67f8de8697 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 09462d246a893a..091cac0ddd5254 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 4577db0bb8f678..51f23edc2f997b 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 f434e114d268a7..0b5b5452283747 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 7bb089e82b9208..c16beeea7a009d 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 30624f5ee10bac..b68ae871451d48 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 e6a89f8692ef02..e0dd0cef088c93 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 f6b2d5c38ff363..0cacaf31bc2765 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 9e69d1eea91af3..e0c207302168a8 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 55e6666c77051a..09fe77ec3b42a5 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 1818e9e3ccf47d..dd1c703e2a6035 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 667bf34ae25d9b..70d32f3dda53a9 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 97cb18e4400bbb..0bd0bfb0411c79 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 65be6a6e983ca4..1c74d87f3afaa5 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 57cc0c3b87ca0f..9ccb0664807bf5 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 eeb1bae84c8f56..9e77f3d94bdd9a 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 ee377649a1719c..1d055d788ceac4 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 58ec54a2d41e02..48886388bfc191 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 5612a02a45c710..b399059beb92c7 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 edd17a5287f01a..ba3f3527c25865 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 dcb40f322d05f0..5f433239b24b67 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 c22ebeec7db0e8..1db62d9d5b5dd3 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(); - - 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.editor.update(cx, |editor, cx| { - editor.insert("\n", cx); - editor.insert(&format!("/{} {}", cmd_name, file_argument), cx); - }); + window + .spawn(cx, |mut cx| async move { + let (paths, dragged_file_worktrees) = paths.await; + let cmd_name = FileSlashCommand.name(); + + 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", 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 c6dac32a073b23..2401f6d70ba605 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 7b1b8c7d4c32c4..9a852bb3d9289d 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 dbb9fb2b8f69b3..bbad1880c6cf6b 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 d00b3a41a94bac..6cecc9470c163a 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 c8911636d07f5d..373e5f09ddcb7f 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 c98182b24d1cd6..12be65b90fd2bd 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 d23647684f95d0..f3811dfa8c140f 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 2279f93b1c942f..1718a750e4ef24 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 d8a4014cfc903d..258869840b583e 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 83f090a4e5d188..b920e1d2177b46 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 8e124412b6e9bc..ea1ae5ab5a5604 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 40b627609d548a..a6222ba822aabd 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 eed3b60761deb5..157c2063ed29b5 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 f9baf7e67590fa..42f814791dce12 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 6fac51143ada83..6881f89a9e2279 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 ba6c4dde39e1d0..0cbd508d1982e5 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 e73d58c7a7df0d..e3a13d40139f55 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 007abeb909c069..523534db92969a 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 b6b7dd57139142..142773891b4f61 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 ce2355afcbf523..10d1d88ae9e219 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 2db21a72acaa4f..6d4ae75dd7c650 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 bcef7e2c086291..a15dc86e280f6e 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 ed926e3e5d7761..930a7fb732f589 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 90204ab024727e..6b75d57de09451 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 29af653e8e89ac..fbe4d42bcb8609 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 663d9078faa220..ed7797843a05b1 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 e09787a91ad9b3..d44d92058dba04 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 a343ce111d88eb..6ff495bdbeec85 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 5abc93deeddf68..2528c4f663362f 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 c99349449529a4..0b4f30da7d0146 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 d225b6a9a39efd..26b4821a6d1af0 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 f22f0c78810913..bbdb0f87c39d53 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 7d145c61b7821c..b0afd6441f9b7a 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 707f2be2bdd624..b9d22b66b48c95 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 75bcd20cd09994..1f5256821e5df6 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 118abcc6046d97..55f08c38a12a1f 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 0f9999b9181190..e46f79e069d61f 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 9114375e88e36e..a54ad7ac2287af 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 33ac333a302698..e99e26983aff43 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 da048d55deeaf9..fc9e6d96cd0a8e 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 21b2279a8f3ce4..e15fd380675421 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 7530c0b2653f72..950a07d86bc1ca 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 16e0107158669f..c512a59375db2c 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 7ad274a1dd1fb8..82539e8187f7c8 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 5186a6d285a9bb..24d05603a50dca 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 dc7527487fb689..1f1a63a10e0a32 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 987c056437a6d5..8cb81816b2ddd4 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 b9547bef1abb42..13b66c7dc3a7e1 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 0a4a259648bb74..1ef78dcdba4b10 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 e5b5b74c16262b..306b1f94260429 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 d627d8fe15a988..7a112d0029b756 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 ef657d37397b3f..779849df246fc6 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 2ecda7d86963b6..5585709d56fa59 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 f64dbc110ef44d..c5b5c6634e3952 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 26f793ba575c05..56ed6e6c036f00 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 5a93c5edd984c8..4b158b6ab1ef5e 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 2427bc4c403fbf..39dacb9700df43 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 a5b27cf288e2ee..bfdae468fbb6cc 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 bd60ee0cd08a2c..b5cf278f706a1b 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 9e5c3dd0485021..d552bba68e0e60 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 d57fc9a2566f1b..ce5d99bbe063a1 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 126db988a1ea8a..9f561ab1b2f10e 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 2ce69efc9b4069..20fa289389aaf7 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 b5bfd0f03b9ec7..83bb8966b7e02c 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 ebde1d9e5073c3..0e8d856221f92d 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 08d2ae7ed164ed..dbc5cd86c25827 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 d9fdab71e86a62..74b3f79d64dd8f 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 75e7c6825f9b13..86b133c08243bc 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 4de368d2ea7756..58aed662b20f5a 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 1c151a730c33d6..fbc1943c97a317 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 ddbc1d197b3388..eb1c56eeb82bca 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 774c105c8f82dc..b250473b61663a 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 30fa54935eb10f..c251204459b0ee 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 13905ead3c92f7..64e0319cbb9775 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 277e9dc80e3535..dcabe8d2167786 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 e12e4b326276ae..2e108686282db2 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 deactivated(&mut self, window: &mut Window, cx: &mut Context) { + self.editor + .update(cx, |item, cx| item.deactivated(window, cx)) } - fn set_nav_history(&mut self, history: ItemNavHistory, cx: &mut ViewContext) { - self.editor - .update(cx, |editor, cx| Item::set_nav_history(editor, history, cx)) + 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, _: &View) -> Option> { + 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 daa1f1440d376d..52b5e35a98e112 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 7a05e6bce404da..dcd1280ec3f8f3 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 b9fa39ed969dc3..555ba426cd8078 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); - - 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; + let channel_name_editor = cx.new(|cx| Editor::single_line(window, cx)); + + 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()) - } - 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()) + .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, } - _ => 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 a4a7acd1e5e9e8..0568aa7faf9589 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 96fe44092d53ae..ac499c589ebeda 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 148e4806cd10a4..dbc408741cda1d 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 574316fa4a586e..4ffb369c53d685 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 7759fef52059fb..f5597895dd62ea 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 14dae9cd2c3a3d..6b2c5dd0454e30 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 cca67cb5e7cf21..1ee4fd480f1076 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 4a55799674de37..d5880dc4b96649 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 c70837444b0189..ca939bcda7b1a6 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 06c43b5611e43b..3133894d806c2b 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 ce0c36300e51f9..2675d244c61914 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)); + fn register( + workspace: &mut Workspace, + _window: Option<&mut Window>, + _: &mut Context, + ) { + workspace.register_action(|workspace, _: &Toggle, window, cx| { + Self::toggle(workspace, "", window, cx) + }); } - pub fn toggle(workspace: &mut Workspace, query: &str, cx: &mut ViewContext) { - let Some(previous_focus_handle) = cx.focused() else { + 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(cx, move |cx| { - CommandPalette::new(previous_focus_handle, query, cx) + workspace.toggle_modal(window, cx, move |window, cx| { + CommandPalette::new(previous_focus_handle, query, window, cx) }); } - fn new(previous_focus_handle: FocusHandle, query: &str, cx: &mut ViewContext) -> Self { + 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 e113fe59ca88ef..3ea94bd10f9c5e 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 64aabb00e836cd..2a9236dd28c8e8 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 84c08d7b2a9836..6189ea4e822bd4 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 161b61b22f23e1..d91c8e2e64392b 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 36fecd2af3dfb3..efbbc6d594e913 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 febbee1cdf4f09..3017a19f4a1e39 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 a4d0f9a8043a7d..697b6da3ce066a 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 68969ca7951efb..d91a15ecfb4b55 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 67280765f66434..2551a754470bdb 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 4391f0a955684c..c130ccb3cc288c 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 73fc9e6a8e861c..0dc03e40375f50 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, window, cx| { + use gpui::Focusable; + window.focus(&editor.focus_handle(cx)); + }) + .unwrap(); + let copilot_provider = cx.new(|_| CopilotCompletionProvider::new(copilot)); editor - .update(cx, |editor, cx| { - editor.set_inline_completion_provider(Some(copilot_provider), cx) + .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, window, cx| { + use gpui::Focusable; + window.focus(&editor.focus_handle(cx)) + }) + .unwrap(); + let copilot_provider = cx.new(|_| CopilotCompletionProvider::new(copilot)); editor - .update(cx, |editor, cx| { - editor.set_inline_completion_provider(Some(copilot_provider), cx) + .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 68f0eed577d855..5d79f00a77a2de 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 98fca60d6312c9..b825855dbe0c51 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 71f96e9f9bc31e..04dfaa7a895e7d 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(); - - 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); + 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(|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 deactivated(&mut self, window: &mut Window, cx: &mut Context) { + self.editor + .update(cx, |editor, cx| editor.deactivated(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| editor.navigate(data, cx)) + .update(cx, |editor, cx| editor.navigate(data, window, cx)) } - fn tab_tooltip_text(&self, _: &AppContext) -> Option { + 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 804be2e6b88ac6..705c70e982fadb 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 a7c916fecc6124..bf3e1c7595ebcc 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 55879d0c426e2b..50d0949b737c08 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 f624225e8aeb5c..26e4ff20f8f4c1 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 488b99c55dd586..f1e862851b6478 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 3b3d3e4630ce71..755f63cc4078da 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 9d828c4de98c9c..3320cf6932145c 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 28aafc1f46c9f4..d85e6bedf5f6eb 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 a9429995d8a971..f513c20689ed90 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 34bdaf4b72d80a..b9d59d65df6023 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 54bb647232299b..14708755084438 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 77d1401e75581d..af11a30ea097e4 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 1f3b985d1f0d5a..6ec334c975cc61 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 9fba4aec25d795..02b0d21ef6e092 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 69ba4ba8a720e9..824f848aed6015 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 30f59be7675409..c1510cd23156c6 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 34dd5ca29943ea..875f05599c911c 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_in(&focus_handle, window, Self::handle_focus_in) .detach(); - cx.on_focus_out(&focus_handle, Self::handle_focus_out) + 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, cx: &WindowContext) -> bool { - self.focus_handle.is_focused(cx) + pub fn is_focused(&self, window: &mut Window) -> bool { + self.focus_handle.is_focused(window) } - 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 52b69833ec71dd..a69988b8e11360 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 50392ab2c9dfec..6275ec97a18ba0 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 b0d1043438864d..c431cd3ae379a4 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 00000000000000..2ac38416327312 --- /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 8a17e7be43a895..de2db3cdd14453 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 4c4ece6cffd3c6..fd71aa6bbd7be6 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.