From afcc0d621b8524d4b3cfa9a5ed19b00c11666348 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 3 Aug 2023 17:03:39 -0600 Subject: [PATCH] WIP --- crates/editor/src/editor_tests.rs | 98 ++++---- crates/editor/src/element.rs | 6 +- crates/editor/src/inlay_hint_cache.rs | 14 +- crates/file_finder/src/file_finder.rs | 20 +- crates/gpui/src/app.rs | 264 ++++++++++++--------- crates/gpui/src/app/test_app_context.rs | 10 +- crates/gpui/src/app/window.rs | 10 +- crates/language_tools/src/lsp_log_tests.rs | 2 +- crates/project_panel/src/project_panel.rs | 8 +- crates/search/src/project_search.rs | 4 +- crates/terminal_view/src/terminal_view.rs | 2 +- crates/workspace/src/workspace.rs | 108 ++++----- crates/zed/src/zed.rs | 6 +- 13 files changed, 295 insertions(+), 257 deletions(-) diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 96921643d45a1b7c1083dab5df471b3bd95adb2d..a114cd437b16bbad580d6e732bb004ac352d822a 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -64,7 +64,7 @@ fn test_edit_events(cx: &mut TestAppContext) { Editor::for_buffer(buffer.clone(), None, cx) } }) - .detach(cx); + .root(cx); let editor2 = cx .add_window({ let events = events.clone(); @@ -81,7 +81,7 @@ fn test_edit_events(cx: &mut TestAppContext) { Editor::for_buffer(buffer.clone(), None, cx) } }) - .detach(cx); + .root(cx); assert_eq!(mem::take(&mut *events.borrow_mut()), []); // Mutating editor 1 will emit an `Edited` event only for that editor. @@ -179,7 +179,7 @@ fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) { let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let editor = cx .add_window(|cx| build_editor(buffer.clone(), cx)) - .detach(cx); + .root(cx); editor.update(cx, |editor, cx| { editor.start_transaction_at(now, cx); @@ -354,7 +354,7 @@ fn test_selection_with_mouse(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\nddddddd\n", cx); build_editor(buffer, cx) }) - .detach(cx); + .root(cx); editor.update(cx, |view, cx| { view.begin_selection(DisplayPoint::new(2, 2), false, 1, cx); }); @@ -423,7 +423,7 @@ fn test_canceling_pending_selection(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx); build_editor(buffer, cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.begin_selection(DisplayPoint::new(2, 2), false, 1, cx); @@ -471,7 +471,7 @@ fn test_clone(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple(&text, cx); build_editor(buffer, cx) }) - .detach(cx); + .root(cx); editor.update(cx, |editor, cx| { editor.change_selections(None, cx, |s| s.select_ranges(selection_ranges.clone())); @@ -489,7 +489,7 @@ fn test_clone(cx: &mut TestAppContext) { .update(cx, |editor, cx| { cx.add_window(Default::default(), |cx| editor.clone(cx)) }) - .detach(cx); + .root(cx); let snapshot = editor.update(cx, |e, cx| e.snapshot(cx)); let cloned_snapshot = cloned_editor.update(cx, |e, cx| e.snapshot(cx)); @@ -639,7 +639,7 @@ fn test_cancel(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx); build_editor(buffer, cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.begin_selection(DisplayPoint::new(3, 4), false, 1, cx); @@ -704,7 +704,7 @@ fn test_fold_action(cx: &mut TestAppContext) { ); build_editor(buffer.clone(), cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { @@ -774,7 +774,7 @@ fn test_move_cursor(cx: &mut TestAppContext) { 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)) - .detach(cx); + .root(cx); buffer.update(cx, |buffer, cx| { buffer.edit( @@ -854,7 +854,7 @@ fn test_move_cursor_multibyte(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcde\nαβγδε\n", cx); build_editor(buffer.clone(), cx) }) - .detach(cx); + .root(cx); assert_eq!('ⓐ'.len_utf8(), 3); assert_eq!('α'.len_utf8(), 2); @@ -961,7 +961,7 @@ fn test_move_cursor_different_line_lengths(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcd\nαβγ\nabcd\nⓐⓑⓒⓓⓔ\n", cx); build_editor(buffer.clone(), cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([empty_range(0, "ⓐⓑⓒⓓⓔ".len())]); @@ -1013,7 +1013,7 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple("abc\n def", cx); build_editor(buffer, cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ @@ -1178,7 +1178,7 @@ fn test_prev_next_word_boundary(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple("use std::str::{foo, bar}\n\n {baz.qux()}", cx); build_editor(buffer, cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ @@ -1233,7 +1233,7 @@ fn test_prev_next_word_bounds_with_soft_wrap(cx: &mut TestAppContext) { MultiBuffer::build_simple("use one::{\n two::three::four::five\n};", cx); build_editor(buffer, cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.set_wrap_width(Some(140.), cx); @@ -1568,7 +1568,7 @@ fn test_delete_to_word_boundary(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple("one two three four", cx); build_editor(buffer.clone(), cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { @@ -1606,7 +1606,7 @@ fn test_newline(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple("aaaa\n bbbb\n", cx); build_editor(buffer.clone(), cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { @@ -1651,7 +1651,7 @@ fn test_newline_with_old_selections(cx: &mut TestAppContext) { }); editor }) - .detach(cx); + .root(cx); editor.update(cx, |editor, cx| { // Edit the buffer directly, deleting ranges surrounding the editor's selections @@ -1863,7 +1863,7 @@ fn test_insert_with_old_selections(cx: &mut TestAppContext) { editor.change_selections(None, cx, |s| s.select_ranges([3..4, 11..12, 19..20])); editor }) - .detach(cx); + .root(cx); editor.update(cx, |editor, cx| { // Edit the buffer directly, deleting ranges surrounding the editor's selections @@ -2375,7 +2375,7 @@ fn test_delete_line(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); build_editor(buffer, cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ @@ -2400,7 +2400,7 @@ fn test_delete_line(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); build_editor(buffer, cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([DisplayPoint::new(2, 0)..DisplayPoint::new(0, 1)]) @@ -2704,7 +2704,7 @@ fn test_duplicate_line(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); build_editor(buffer, cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ @@ -2732,7 +2732,7 @@ fn test_duplicate_line(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); build_editor(buffer, cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ @@ -2761,7 +2761,7 @@ fn test_move_line_up_down(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx); build_editor(buffer, cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.fold_ranges( vec![ @@ -2862,7 +2862,7 @@ fn test_move_line_up_down_with_blocks(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx); build_editor(buffer, cx) }) - .detach(cx); + .root(cx); editor.update(cx, |editor, cx| { let snapshot = editor.buffer.read(cx).snapshot(cx); editor.insert_blocks( @@ -3182,7 +3182,7 @@ fn test_select_all(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple("abc\nde\nfgh", cx); build_editor(buffer, cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.select_all(&SelectAll, cx); assert_eq!( @@ -3201,7 +3201,7 @@ fn test_select_line(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple(&sample_text(6, 5, 'a'), cx); build_editor(buffer, cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ @@ -3250,7 +3250,7 @@ fn test_split_selection_into_lines(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple(&sample_text(9, 5, 'a'), cx); build_editor(buffer, cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.fold_ranges( vec![ @@ -3323,7 +3323,7 @@ fn test_add_selection_above_below(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple("abc\ndefghi\n\njk\nlmno\n", cx); build_editor(buffer, cx) }) - .detach(cx); + .root(cx); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { @@ -3608,7 +3608,7 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); - let view = cx.add_window(|cx| build_editor(buffer, cx)).detach(cx); + let view = cx.add_window(|cx| build_editor(buffer, cx)).root(cx); view.condition(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) .await; @@ -3771,7 +3771,7 @@ async fn test_autoindent_selections(cx: &mut gpui::TestAppContext) { let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); - let editor = cx.add_window(|cx| build_editor(buffer, cx)).detach(cx); + let editor = cx.add_window(|cx| build_editor(buffer, cx)).root(cx); editor .condition(cx, |editor, cx| !editor.buffer.read(cx).is_parsing(cx)) .await; @@ -4334,7 +4334,7 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); - let view = cx.add_window(|cx| build_editor(buffer, cx)).detach(cx); + let view = cx.add_window(|cx| build_editor(buffer, cx)).root(cx); view.condition(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) .await; @@ -4482,7 +4482,7 @@ async fn test_delete_autoclose_pair(cx: &mut gpui::TestAppContext) { let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); - let editor = cx.add_window(|cx| build_editor(buffer, cx)).detach(cx); + let editor = cx.add_window(|cx| build_editor(buffer, cx)).root(cx); editor .condition(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) .await; @@ -4572,7 +4572,7 @@ async fn test_snippets(cx: &mut gpui::TestAppContext) { ); let buffer = cx.update(|cx| MultiBuffer::build_simple(&text, cx)); - let editor = cx.add_window(|cx| build_editor(buffer, cx)).detach(cx); + let editor = cx.add_window(|cx| build_editor(buffer, cx)).root(cx); editor.update(cx, |editor, cx| { let snippet = Snippet::parse("f(${1:one}, ${2:two}, ${1:three})$0").unwrap(); @@ -4702,7 +4702,7 @@ async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) { let fake_server = fake_servers.next().await.unwrap(); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); - let editor = cx.add_window(|cx| build_editor(buffer, cx)).detach(cx); + let editor = cx.add_window(|cx| build_editor(buffer, cx)).root(cx); editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx)); assert!(cx.read(|cx| editor.is_dirty(cx))); @@ -4814,7 +4814,7 @@ async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) { let fake_server = fake_servers.next().await.unwrap(); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); - let editor = cx.add_window(|cx| build_editor(buffer, cx)).detach(cx); + let editor = cx.add_window(|cx| build_editor(buffer, cx)).root(cx); editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx)); assert!(cx.read(|cx| editor.is_dirty(cx))); @@ -4928,7 +4928,7 @@ async fn test_document_format_manual_trigger(cx: &mut gpui::TestAppContext) { let fake_server = fake_servers.next().await.unwrap(); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); - let editor = cx.add_window(|cx| build_editor(buffer, cx)).detach(cx); + let editor = cx.add_window(|cx| build_editor(buffer, cx)).root(cx); editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx)); let format = editor.update(cx, |editor, cx| { @@ -5706,7 +5706,7 @@ fn test_editing_disjoint_excerpts(cx: &mut TestAppContext) { multibuffer }); - let view = cx.add_window(|cx| build_editor(multibuffer, cx)).detach(cx); + let view = cx.add_window(|cx| build_editor(multibuffer, cx)).root(cx); view.update(cx, |view, cx| { assert_eq!(view.text(cx), "aaaa\nbbbb"); view.change_selections(None, cx, |s| { @@ -5776,7 +5776,7 @@ fn test_editing_overlapping_excerpts(cx: &mut TestAppContext) { multibuffer }); - let view = cx.add_window(|cx| build_editor(multibuffer, cx)).detach(cx); + let view = cx.add_window(|cx| build_editor(multibuffer, cx)).root(cx); view.update(cx, |view, cx| { let (expected_text, selection_ranges) = marked_text_ranges( indoc! {" @@ -5869,7 +5869,7 @@ fn test_refresh_selections(cx: &mut TestAppContext) { ); editor }) - .detach(cx); + .root(cx); // Refreshing selections is a no-op when excerpts haven't changed. editor.update(cx, |editor, cx| { @@ -5950,7 +5950,7 @@ fn test_refresh_selections_while_selecting_with_mouse(cx: &mut TestAppContext) { ); editor }) - .detach(cx); + .root(cx); multibuffer.update(cx, |multibuffer, cx| { multibuffer.remove_excerpts([excerpt1_id.unwrap()], cx); @@ -6013,7 +6013,7 @@ async fn test_extra_newline_insertion(cx: &mut gpui::TestAppContext) { let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); - let view = cx.add_window(|cx| build_editor(buffer, cx)).detach(cx); + let view = cx.add_window(|cx| build_editor(buffer, cx)).root(cx); view.condition(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) .await; @@ -6054,7 +6054,7 @@ fn test_highlighted_ranges(cx: &mut TestAppContext) { let buffer = MultiBuffer::build_simple(&sample_text(16, 8, 'a'), cx); build_editor(buffer.clone(), cx) }) - .detach(cx); + .root(cx); editor.update(cx, |editor, cx| { struct Type1; @@ -6145,7 +6145,7 @@ async fn test_following(cx: &mut gpui::TestAppContext) { }); let leader = cx .add_window(|cx| build_editor(buffer.clone(), cx)) - .detach(cx); + .root(cx); let follower = cx .update(|cx| { cx.add_window( @@ -6156,7 +6156,7 @@ async fn test_following(cx: &mut gpui::TestAppContext) { |cx| build_editor(buffer.clone(), cx), ) }) - .detach(cx); + .root(cx); let is_still_following = Rc::new(RefCell::new(true)); let follower_edit_event_count = Rc::new(RefCell::new(0)); @@ -6289,7 +6289,7 @@ async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) { let project = Project::test(fs, ["/file.rs".as_ref()], cx).await; let workspace = cx .add_window(|cx| Workspace::test_new(project.clone(), cx)) - .detach(cx); + .root(cx); let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone()); let leader = pane.update(cx, |_, cx| { @@ -7033,7 +7033,7 @@ async fn test_copilot_multibuffer( ); multibuffer }); - let editor = cx.add_window(|cx| build_editor(multibuffer, cx)).detach(cx); + let editor = cx.add_window(|cx| build_editor(multibuffer, cx)).root(cx); handle_copilot_completion_request( &copilot_lsp, @@ -7163,7 +7163,7 @@ async fn test_copilot_disabled_globs( ); multibuffer }); - let editor = cx.add_window(|cx| build_editor(multibuffer, cx)).detach(cx); + let editor = cx.add_window(|cx| build_editor(multibuffer, cx)).root(cx); let mut copilot_requests = copilot_lsp .handle_request::(move |_params, _cx| async move { @@ -7244,7 +7244,7 @@ async fn test_on_type_formatting_not_triggered(cx: &mut gpui::TestAppContext) { project.update(cx, |project, _| project.languages().add(Arc::new(language))); let workspace = cx .add_window(|cx| Workspace::test_new(project.clone(), cx)) - .detach(cx); + .root(cx); let worktree_id = workspace.update(cx, |workspace, cx| { workspace.project().read_with(cx, |project, cx| { project.worktrees(cx).next().unwrap().read(cx).id() diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index dc40e7fb8568aeec2bf5d4fe6f4168e4847c3558..2d4b273f5ef0523f8ef8d9d9cd107c7e30bd659d 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -3007,7 +3007,7 @@ mod tests { let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx); Editor::new(EditorMode::Full, buffer, None, None, cx) }) - .detach(cx); + .root(cx); let element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx))); let layouts = editor.update(cx, |editor, cx| { @@ -3028,7 +3028,7 @@ mod tests { let buffer = MultiBuffer::build_simple("", cx); Editor::new(EditorMode::Full, buffer, None, None, cx) }) - .detach(cx); + .root(cx); editor.update(cx, |editor, cx| { editor.set_placeholder_text("hello", cx); @@ -3240,7 +3240,7 @@ mod tests { let buffer = MultiBuffer::build_simple(&input_text, cx); Editor::new(editor_mode, buffer, None, None, cx) }) - .detach(cx); + .root(cx); let mut element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx))); let (_, layout_state) = editor.update(cx, |editor, cx| { diff --git a/crates/editor/src/inlay_hint_cache.rs b/crates/editor/src/inlay_hint_cache.rs index 089cbb29958c727a0b7760018833a279534a225a..47a27c049f91658fdd848381f86207642bce15c9 100644 --- a/crates/editor/src/inlay_hint_cache.rs +++ b/crates/editor/src/inlay_hint_cache.rs @@ -1138,7 +1138,7 @@ mod tests { let project = Project::test(fs, ["/a".as_ref()], cx).await; let workspace = cx .add_window(|cx| Workspace::test_new(project.clone(), cx)) - .detach(cx); + .root(cx); let worktree_id = workspace.update(cx, |workspace, cx| { workspace.project().read_with(cx, |project, cx| { project.worktrees(cx).next().unwrap().read(cx).id() @@ -1840,7 +1840,7 @@ mod tests { project.update(cx, |project, _| project.languages().add(Arc::new(language))); let workspace = cx .add_window(|cx| Workspace::test_new(project.clone(), cx)) - .detach(cx); + .root(cx); let worktree_id = workspace.update(cx, |workspace, cx| { workspace.project().read_with(cx, |project, cx| { project.worktrees(cx).next().unwrap().read(cx).id() @@ -1995,7 +1995,7 @@ mod tests { }); let workspace = cx .add_window(|cx| Workspace::test_new(project.clone(), cx)) - .detach(cx); + .root(cx); let worktree_id = workspace.update(cx, |workspace, cx| { workspace.project().read_with(cx, |project, cx| { project.worktrees(cx).next().unwrap().read(cx).id() @@ -2083,7 +2083,7 @@ mod tests { cx.foreground().run_until_parked(); let editor = cx .add_window(|cx| Editor::for_multibuffer(multibuffer, Some(project.clone()), cx)) - .detach(cx); + .root(cx); let editor_edited = Arc::new(AtomicBool::new(false)); let fake_server = fake_servers.next().await.unwrap(); let closure_editor_edited = Arc::clone(&editor_edited); @@ -2337,7 +2337,7 @@ all hints should be invalidated and requeried for all of its visible excerpts" }); let workspace = cx .add_window(|cx| Workspace::test_new(project.clone(), cx)) - .detach(cx); + .root(cx); let worktree_id = workspace.update(cx, |workspace, cx| { workspace.project().read_with(cx, |project, cx| { project.worktrees(cx).next().unwrap().read(cx).id() @@ -2384,7 +2384,7 @@ all hints should be invalidated and requeried for all of its visible excerpts" cx.foreground().run_until_parked(); let editor = cx .add_window(|cx| Editor::for_multibuffer(multibuffer, Some(project.clone()), cx)) - .detach(cx); + .root(cx); let editor_edited = Arc::new(AtomicBool::new(false)); let fake_server = fake_servers.next().await.unwrap(); let closure_editor_edited = Arc::clone(&editor_edited); @@ -2574,7 +2574,7 @@ all hints should be invalidated and requeried for all of its visible excerpts" project.update(cx, |project, _| project.languages().add(Arc::new(language))); let workspace = cx .add_window(|cx| Workspace::test_new(project.clone(), cx)) - .detach(cx); + .root(cx); let worktree_id = workspace.update(cx, |workspace, cx| { workspace.project().read_with(cx, |project, cx| { project.worktrees(cx).next().unwrap().read(cx).id() diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 2c9d9c0c71e390c256e7db785ee06d707039a8a1..12bf3242627619d390409bba044c0fa9cdcce3d4 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -842,7 +842,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/dir".as_ref()], cx).await; let workspace = cx .add_window(|cx| Workspace::test_new(project, cx)) - .detach(cx); + .root(cx); let finder = cx .add_window(|cx| { Picker::new( @@ -856,7 +856,7 @@ mod tests { cx, ) }) - .detach(cx); + .root(cx); let query = test_path_like("hi"); finder @@ -940,7 +940,7 @@ mod tests { .await; let workspace = cx .add_window(|cx| Workspace::test_new(project, cx)) - .detach(cx); + .root(cx); let finder = cx .add_window(|cx| { Picker::new( @@ -954,7 +954,7 @@ mod tests { cx, ) }) - .detach(cx); + .root(cx); finder .update(cx, |f, cx| { f.delegate_mut().spawn_search(test_path_like("hi"), cx) @@ -980,7 +980,7 @@ mod tests { .await; let workspace = cx .add_window(|cx| Workspace::test_new(project, cx)) - .detach(cx); + .root(cx); let finder = cx .add_window(|cx| { Picker::new( @@ -994,7 +994,7 @@ mod tests { cx, ) }) - .detach(cx); + .root(cx); // Even though there is only one worktree, that worktree's filename // is included in the matching, because the worktree is a single file. @@ -1051,7 +1051,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; let workspace = cx .add_window(|cx| Workspace::test_new(project, cx)) - .detach(cx); + .root(cx); let worktree_id = cx.read(|cx| { let worktrees = workspace.read(cx).worktrees(cx).collect::>(); assert_eq!(worktrees.len(), 1); @@ -1078,7 +1078,7 @@ mod tests { cx, ) }) - .detach(cx); + .root(cx); finder .update(cx, |f, cx| { @@ -1117,7 +1117,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; let workspace = cx .add_window(|cx| Workspace::test_new(project, cx)) - .detach(cx); + .root(cx); let finder = cx .add_window(|cx| { Picker::new( @@ -1131,7 +1131,7 @@ mod tests { cx, ) }) - .detach(cx); + .root(cx); finder .update(cx, |f, cx| { f.delegate_mut().spawn_search(test_path_like("dir"), cx) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 9b847e9c0cfdea426902ea59e93cec3a0c349fdf..dce0b0e5f0ceca28e7503027720cfc39be351e24 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -130,12 +130,12 @@ pub trait BorrowAppContext { } pub trait BorrowWindowContext { - type Return; + type Result; - fn read_with(&self, window_id: usize, f: F) -> Self::Return + fn read_window_with(&self, window_id: usize, f: F) -> Self::Result where F: FnOnce(&WindowContext) -> T; - fn update(&mut self, window_id: usize, f: F) -> Self::Return + fn update_window(&mut self, window_id: usize, f: F) -> Self::Result where F: FnOnce(&mut WindowContext) -> T; } @@ -458,6 +458,26 @@ impl BorrowAppContext for AsyncAppContext { } } +impl BorrowWindowContext for AsyncAppContext { + type Result = Option; + + fn read_window_with(&self, window_id: usize, f: F) -> Self::Result + where + F: FnOnce(&WindowContext) -> T, + { + self.0.borrow().read_with(|cx| cx.read_window(window_id, f)) + } + + fn update_window(&mut self, window_id: usize, f: F) -> Self::Result + where + F: FnOnce(&mut WindowContext) -> T, + { + self.0 + .borrow_mut() + .update(|cx| cx.update_window(window_id, f)) + } +} + type ActionCallback = dyn FnMut(&mut dyn AnyView, &dyn Action, &mut WindowContext, usize); type GlobalActionCallback = dyn FnMut(&dyn Action, &mut AppContext); @@ -2162,6 +2182,24 @@ impl BorrowAppContext for AppContext { } } +impl BorrowWindowContext for AppContext { + type Result = Option; + + fn read_window_with(&self, window_id: usize, f: F) -> Self::Result + where + F: FnOnce(&WindowContext) -> T, + { + AppContext::read_window(self, window_id, f) + } + + fn update_window(&mut self, window_id: usize, f: F) -> Self::Result + where + F: FnOnce(&mut WindowContext) -> T, + { + AppContext::update_window(self, window_id, f) + } +} + #[derive(Debug)] pub enum ParentId { View(usize), @@ -3360,14 +3398,18 @@ impl BorrowAppContext for ViewContext<'_, '_, V> { } impl BorrowWindowContext for ViewContext<'_, '_, V> { - type Return = T; + type Result = T; - fn read_with T>(&self, window_id: usize, f: F) -> T { - BorrowWindowContext::read_with(&*self.window_context, window_id, f) + fn read_window_with T>(&self, window_id: usize, f: F) -> T { + BorrowWindowContext::read_window_with(&*self.window_context, window_id, f) } - fn update T>(&mut self, window_id: usize, f: F) -> T { - BorrowWindowContext::update(&mut *self.window_context, window_id, f) + fn update_window T>( + &mut self, + window_id: usize, + f: F, + ) -> T { + BorrowWindowContext::update_window(&mut *self.window_context, window_id, f) } } @@ -3467,14 +3509,18 @@ impl BorrowAppContext for LayoutContext<'_, '_, '_, V> { } impl BorrowWindowContext for LayoutContext<'_, '_, '_, V> { - type Return = T; + type Result = T; - fn read_with T>(&self, window_id: usize, f: F) -> T { - BorrowWindowContext::read_with(&*self.view_context, window_id, f) + fn read_window_with T>(&self, window_id: usize, f: F) -> T { + BorrowWindowContext::read_window_with(&*self.view_context, window_id, f) } - fn update T>(&mut self, window_id: usize, f: F) -> T { - BorrowWindowContext::update(&mut *self.view_context, window_id, f) + fn update_window T>( + &mut self, + window_id: usize, + f: F, + ) -> T { + BorrowWindowContext::update_window(&mut *self.view_context, window_id, f) } } @@ -3521,14 +3567,18 @@ impl BorrowAppContext for EventContext<'_, '_, '_, V> { } impl BorrowWindowContext for EventContext<'_, '_, '_, V> { - type Return = T; + type Result = T; - fn read_with T>(&self, window_id: usize, f: F) -> T { - BorrowWindowContext::read_with(&*self.view_context, window_id, f) + fn read_window_with T>(&self, window_id: usize, f: F) -> T { + BorrowWindowContext::read_window_with(&*self.view_context, window_id, f) } - fn update T>(&mut self, window_id: usize, f: F) -> T { - BorrowWindowContext::update(&mut *self.view_context, window_id, f) + fn update_window T>( + &mut self, + window_id: usize, + f: F, + ) -> T { + BorrowWindowContext::update_window(&mut *self.view_context, window_id, f) } } @@ -3830,32 +3880,16 @@ impl WindowHandle { self.any_handle.id() } - pub fn root(&self, cx: &impl BorrowAppContext) -> ViewHandle { + pub fn root(&self, cx: &C) -> C::Result> { self.read_with(cx, |cx| cx.root_view().clone().downcast().unwrap()) } - /// Keep this window open until it's explicitly closed. - // - // TODO: Implement window dropping behavior when we don't call this. - pub fn detach(mut self, cx: &impl BorrowAppContext) -> ViewHandle { - let root = self.root(cx); - let ref_counts = self.any_handle.ref_counts.take(); - #[cfg(any(test, feature = "test-support"))] - ref_counts - .unwrap() - .lock() - .leak_detector - .lock() - .handle_dropped(self.id(), self.any_handle.handle_id); - root - } - - pub fn read_with(&self, cx: &C, read: F) -> R + pub fn read_with(&self, cx: &C, read: F) -> C::Result where - C: BorrowAppContext, + C: BorrowWindowContext, F: FnOnce(&WindowContext) -> R, { - cx.read_with(|cx| cx.read_window(self.id(), read).unwrap()) + cx.read_window_with(self.id(), |cx| read(cx)) } pub fn update(&self, cx: &mut C, update: F) -> R @@ -3891,9 +3925,9 @@ impl WindowHandle { root_view.read(cx) } - pub fn read_root_with(&self, cx: &C, read: F) -> R + pub fn read_root_with(&self, cx: &C, read: F) -> C::Result where - C: BorrowAppContext, + C: BorrowWindowContext, F: FnOnce(&V, &ViewContext) -> R, { self.read_with(cx, |cx| { @@ -4021,25 +4055,25 @@ impl ViewHandle { cx.read_view(self) } - pub fn read_with(&self, cx: &C, read: F) -> C::Return + pub fn read_with(&self, cx: &C, read: F) -> C::Result where C: BorrowWindowContext, F: FnOnce(&T, &ViewContext) -> S, { - cx.read_with(self.window_id, |cx| { + cx.read_window_with(self.window_id, |cx| { let cx = ViewContext::immutable(cx, self.view_id); read(cx.read_view(self), &cx) }) } - pub fn update(&self, cx: &mut C, update: F) -> C::Return + pub fn update(&self, cx: &mut C, update: F) -> C::Result where C: BorrowWindowContext, F: FnOnce(&mut T, &mut ViewContext) -> S, { let mut update = Some(update); - cx.update(self.window_id, |cx| { + cx.update_window(self.window_id, |cx| { cx.update_view(self, &mut |view, cx| { let update = update.take().unwrap(); update(view, cx) @@ -5005,7 +5039,7 @@ mod tests { } #[crate::test(self)] - fn test_entity_release_hooks(cx: &mut AppContext) { + fn test_entity_release_hooks(cx: &mut TestAppContext) { struct Model { released: Rc>, } @@ -5048,7 +5082,7 @@ mod tests { let model = cx.add_model(|_| Model { released: model_released.clone(), }); - let window = cx.add_window(Default::default(), |_| View { + let window = cx.add_window(|_| View { released: view_released.clone(), }); let view = window.root(cx); @@ -5056,16 +5090,18 @@ mod tests { assert!(!model_released.get()); assert!(!view_released.get()); - cx.observe_release(&model, { - let model_release_observed = model_release_observed.clone(); - move |_, _| model_release_observed.set(true) - }) - .detach(); - cx.observe_release(&view, { - let view_release_observed = view_release_observed.clone(); - move |_, _| view_release_observed.set(true) - }) - .detach(); + cx.update(|cx| { + cx.observe_release(&model, { + let model_release_observed = model_release_observed.clone(); + move |_, _| model_release_observed.set(true) + }) + .detach(); + cx.observe_release(&view, { + let view_release_observed = view_release_observed.clone(); + move |_, _| view_release_observed.set(true) + }) + .detach(); + }); cx.update(move |_| { drop(model); @@ -5795,7 +5831,7 @@ mod tests { } #[crate::test(self)] - fn test_dispatch_action(cx: &mut AppContext) { + fn test_dispatch_action(cx: &mut TestAppContext) { struct ViewA { id: usize, child: Option, @@ -5846,68 +5882,70 @@ mod tests { impl_actions!(test, [Action]); let actions = Rc::new(RefCell::new(Vec::new())); + let observed_actions = Rc::new(RefCell::new(Vec::new())); - cx.add_global_action({ - let actions = actions.clone(); - move |_: &Action, _: &mut AppContext| { - actions.borrow_mut().push("global".to_string()); - } - }); + cx.update(|cx| { + cx.add_global_action({ + let actions = actions.clone(); + move |_: &Action, _: &mut AppContext| { + actions.borrow_mut().push("global".to_string()); + } + }); - cx.add_action({ - let actions = actions.clone(); - move |view: &mut ViewA, action: &Action, cx| { - assert_eq!(action.0, "bar"); - cx.propagate_action(); - actions.borrow_mut().push(format!("{} a", view.id)); - } - }); + cx.add_action({ + let actions = actions.clone(); + move |view: &mut ViewA, action: &Action, cx| { + assert_eq!(action.0, "bar"); + cx.propagate_action(); + actions.borrow_mut().push(format!("{} a", view.id)); + } + }); - cx.add_action({ - let actions = actions.clone(); - move |view: &mut ViewA, _: &Action, cx| { - if view.id != 1 { - cx.add_view(|cx| { - cx.propagate_action(); // Still works on a nested ViewContext - ViewB { id: 5, child: None } - }); + cx.add_action({ + let actions = actions.clone(); + move |view: &mut ViewA, _: &Action, cx| { + if view.id != 1 { + cx.add_view(|cx| { + cx.propagate_action(); // Still works on a nested ViewContext + ViewB { id: 5, child: None } + }); + } + actions.borrow_mut().push(format!("{} b", view.id)); } - actions.borrow_mut().push(format!("{} b", view.id)); - } - }); + }); - cx.add_action({ - let actions = actions.clone(); - move |view: &mut ViewB, _: &Action, cx| { - cx.propagate_action(); - actions.borrow_mut().push(format!("{} c", view.id)); - } - }); + cx.add_action({ + let actions = actions.clone(); + move |view: &mut ViewB, _: &Action, cx| { + cx.propagate_action(); + actions.borrow_mut().push(format!("{} c", view.id)); + } + }); - cx.add_action({ - let actions = actions.clone(); - move |view: &mut ViewB, _: &Action, cx| { - cx.propagate_action(); - actions.borrow_mut().push(format!("{} d", view.id)); - } - }); + cx.add_action({ + let actions = actions.clone(); + move |view: &mut ViewB, _: &Action, cx| { + cx.propagate_action(); + actions.borrow_mut().push(format!("{} d", view.id)); + } + }); - cx.capture_action({ - let actions = actions.clone(); - move |view: &mut ViewA, _: &Action, cx| { - cx.propagate_action(); - actions.borrow_mut().push(format!("{} capture", view.id)); - } - }); + cx.capture_action({ + let actions = actions.clone(); + move |view: &mut ViewA, _: &Action, cx| { + cx.propagate_action(); + actions.borrow_mut().push(format!("{} capture", view.id)); + } + }); - let observed_actions = Rc::new(RefCell::new(Vec::new())); - cx.observe_actions({ - let observed_actions = observed_actions.clone(); - move |action_id, _| observed_actions.borrow_mut().push(action_id) - }) - .detach(); + cx.observe_actions({ + let observed_actions = observed_actions.clone(); + move |action_id, _| observed_actions.borrow_mut().push(action_id) + }) + .detach(); + }); - let window = cx.add_window(Default::default(), |_| ViewA { id: 1, child: None }); + let window = cx.add_window(|_| ViewA { id: 1, child: None }); let view_1 = window.root(cx); let view_2 = window.update(cx, |cx| { let child = cx.add_view(|_| ViewB { id: 2, child: None }); @@ -5956,7 +5994,7 @@ mod tests { // Remove view_1, which doesn't propagate the action - let window = cx.add_window(Default::default(), |_| ViewB { id: 2, child: None }); + let window = cx.add_window(|_| ViewB { id: 2, child: None }); let view_2 = window.root(cx); let view_3 = window.update(cx, |cx| { let child = cx.add_view(|_| ViewA { id: 3, child: None }); @@ -6457,7 +6495,7 @@ mod tests { } #[crate::test(self)] - fn test_refresh_windows(cx: &mut AppContext) { + fn test_refresh_windows(cx: &mut TestAppContext) { struct View(usize); impl super::Entity for View { @@ -6474,7 +6512,7 @@ mod tests { } } - let window = cx.add_window(Default::default(), |_| View(0)); + let window = cx.add_window(|_| View(0)); let root_view = window.root(cx); window.update(cx, |cx| { assert_eq!( diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index 5c7947a44827d3eb23e6a490c7fdfaacd9e90bfb..0165c52e9f3fff9453c43484208c202a6a39138a 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -406,16 +406,20 @@ impl BorrowAppContext for TestAppContext { } impl BorrowWindowContext for TestAppContext { - type Return = T; + type Result = T; - fn read_with T>(&self, window_id: usize, f: F) -> T { + fn read_window_with T>(&self, window_id: usize, f: F) -> T { self.cx .borrow() .read_window(window_id, f) .expect("window was closed") } - fn update T>(&mut self, window_id: usize, f: F) -> T { + fn update_window T>( + &mut self, + window_id: usize, + f: F, + ) -> T { self.cx .borrow_mut() .update_window(window_id, f) diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 671d2b38c77c9d71201e77c87fd8ef21d077b24b..0149c310daaadd773e54dd58314261eb1864ecb6 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -142,9 +142,9 @@ impl BorrowAppContext for WindowContext<'_> { } impl BorrowWindowContext for WindowContext<'_> { - type Return = T; + type Result = T; - fn read_with T>(&self, window_id: usize, f: F) -> T { + fn read_window_with T>(&self, window_id: usize, f: F) -> T { if self.window_id == window_id { f(self) } else { @@ -152,7 +152,11 @@ impl BorrowWindowContext for WindowContext<'_> { } } - fn update T>(&mut self, window_id: usize, f: F) -> T { + fn update_window T>( + &mut self, + window_id: usize, + f: F, + ) -> T { if self.window_id == window_id { f(self) } else { diff --git a/crates/language_tools/src/lsp_log_tests.rs b/crates/language_tools/src/lsp_log_tests.rs index ce05a417ad8fc6cebc61ee236d2289b8b73e2170..d26000ebc73b022c15dbf02ccdb3053763264118 100644 --- a/crates/language_tools/src/lsp_log_tests.rs +++ b/crates/language_tools/src/lsp_log_tests.rs @@ -63,7 +63,7 @@ async fn test_lsp_logs(cx: &mut TestAppContext) { let log_view = cx .add_window(|cx| LspLogView::new(project.clone(), log_store.clone(), cx)) - .detach(cx); + .root(cx); language_server.notify::(lsp::LogMessageParams { message: "hello from the server".into(), diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index fdc5ea108a812459f374fdd0a1386fe31bb9830a..021ea2d3bc3a817342e9eac684496ffeee5026bb 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1782,7 +1782,7 @@ mod tests { let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await; let workspace = cx .add_window(|cx| Workspace::test_new(project.clone(), cx)) - .detach(cx); + .root(cx); let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx)); assert_eq!( visible_entries_as_strings(&panel, 0..50, cx), @@ -2327,7 +2327,7 @@ mod tests { let project = Project::test(fs.clone(), ["/root1".as_ref()], cx).await; let workspace = cx .add_window(|cx| Workspace::test_new(project.clone(), cx)) - .detach(cx); + .root(cx); let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx)); panel.update(cx, |panel, cx| { @@ -2641,7 +2641,7 @@ mod tests { let project = Project::test(fs.clone(), ["/src".as_ref()], cx).await; let workspace = cx .add_window(|cx| Workspace::test_new(project.clone(), cx)) - .detach(cx); + .root(cx); let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx)); let new_search_events_count = Arc::new(AtomicUsize::new(0)); @@ -2730,7 +2730,7 @@ mod tests { let project = Project::test(fs.clone(), ["/project_root".as_ref()], cx).await; let workspace = cx .add_window(|cx| Workspace::test_new(project.clone(), cx)) - .detach(cx); + .root(cx); let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx)); panel.update(cx, |panel, cx| { diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index e57edd3b14709aea1056965b59e173bc9e404a23..0db66b4e378a56c97e2e2d1290742e52e1329bda 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -1449,7 +1449,7 @@ pub mod tests { let search = cx.add_model(|cx| ProjectSearch::new(project, cx)); let search_view = cx .add_window(|cx| ProjectSearchView::new(search.clone(), cx)) - .detach(cx); + .root(cx); search_view.update(cx, |search_view, cx| { search_view @@ -1754,7 +1754,7 @@ pub mod tests { }); let workspace = cx .add_window(|cx| Workspace::test_new(project, cx)) - .detach(cx); + .root(cx); let active_item = cx.read(|cx| { workspace diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 874978b4fc567526e6bd17d4f6edd3fa9a670c3c..a600046ac2861fb7b0b1250c65d4b31c1af3166c 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -1072,7 +1072,7 @@ mod tests { let project = Project::test(params.fs.clone(), [], cx).await; let workspace = cx .add_window(|cx| Workspace::test_new(project.clone(), cx)) - .detach(cx); + .root(cx); (project, workspace) } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 3222ea2eb8cab97976c81ad6ad5c43668cf46655..2efa9f8daac69c872bda6cb3f7936d52d8d0222b 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -793,68 +793,60 @@ impl Workspace { DB.next_id().await.unwrap_or(0) }; - let window = requesting_window_id - .and_then(|window_id| { - cx.update(|cx| { - cx.replace_root_view(window_id, |cx| { - Workspace::new( - workspace_id, - project_handle.clone(), - app_state.clone(), - cx, - ) - }) + let window = requesting_window_id.and_then(|window_id| { + cx.update(|cx| { + cx.replace_root_view(window_id, |cx| { + Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx) }) }) - .unwrap_or_else(|| { - let window_bounds_override = window_bounds_env_override(&cx); - let (bounds, display) = if let Some(bounds) = window_bounds_override { - (Some(bounds), None) - } else { - serialized_workspace - .as_ref() - .and_then(|serialized_workspace| { - let display = serialized_workspace.display?; - let mut bounds = serialized_workspace.bounds?; - - // Stored bounds are relative to the containing display. - // So convert back to global coordinates if that screen still exists - if let WindowBounds::Fixed(mut window_bounds) = bounds { - if let Some(screen) = cx.platform().screen_by_id(display) { - let screen_bounds = screen.bounds(); - window_bounds.set_origin_x( - window_bounds.origin_x() + screen_bounds.origin_x(), - ); - window_bounds.set_origin_y( - window_bounds.origin_y() + screen_bounds.origin_y(), - ); - bounds = WindowBounds::Fixed(window_bounds); - } else { - // Screen no longer exists. Return none here. - return None; - } + }); + let window = window.unwrap_or_else(|| { + let window_bounds_override = window_bounds_env_override(&cx); + let (bounds, display) = if let Some(bounds) = window_bounds_override { + (Some(bounds), None) + } else { + serialized_workspace + .as_ref() + .and_then(|serialized_workspace| { + let display = serialized_workspace.display?; + let mut bounds = serialized_workspace.bounds?; + + // Stored bounds are relative to the containing display. + // So convert back to global coordinates if that screen still exists + if let WindowBounds::Fixed(mut window_bounds) = bounds { + if let Some(screen) = cx.platform().screen_by_id(display) { + let screen_bounds = screen.bounds(); + window_bounds.set_origin_x( + window_bounds.origin_x() + screen_bounds.origin_x(), + ); + window_bounds.set_origin_y( + window_bounds.origin_y() + screen_bounds.origin_y(), + ); + bounds = WindowBounds::Fixed(window_bounds); + } else { + // Screen no longer exists. Return none here. + return None; } + } - Some((bounds, display)) - }) - .unzip() - }; - - // Use the serialized workspace to construct the new window - cx.add_window( - (app_state.build_window_options)(bounds, display, cx.platform().as_ref()), - |cx| { - Workspace::new( - workspace_id, - project_handle.clone(), - app_state.clone(), - cx, - ) - }, - ) - }); + Some((bounds, display)) + }) + .unzip() + }; + + // Use the serialized workspace to construct the new window + cx.add_window( + (app_state.build_window_options)(bounds, display, cx.platform().as_ref()), + |cx| { + Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx) + }, + ) + }); + + // We haven't yielded the main thread since obtaining the window handle, + // so the window exists. + let workspace = window.root(&cx).unwrap(); - let workspace = window.root(&cx); (app_state.initialize_workspace)( workspace.downgrade(), serialized_workspace.is_some(), @@ -3985,7 +3977,7 @@ pub fn join_remote_project( ), |cx| Workspace::new(0, project, app_state.clone(), cx), ); - let workspace = window.root(&cx); + let workspace = window.root(&cx).unwrap(); (app_state.initialize_workspace)( workspace.downgrade(), false, diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 1770c5648e1fd2f8fe2a5ed31354f5525629a04f..a459122cfc9a29b209f8d6cbcf7031f739781857 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -985,7 +985,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; let workspace = cx .add_window(|cx| Workspace::test_new(project, cx)) - .detach(cx); + .root(cx); let entries = cx.read(|cx| workspace.file_project_paths(cx)); let file1 = entries[0].clone(); @@ -1566,7 +1566,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; let workspace = cx .add_window(|cx| Workspace::test_new(project.clone(), cx)) - .detach(cx); + .root(cx); let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone()); let entries = cx.read(|cx| workspace.file_project_paths(cx)); @@ -1845,7 +1845,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; let workspace = cx .add_window(|cx| Workspace::test_new(project, cx)) - .detach(cx); + .root(cx); let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone()); let entries = cx.read(|cx| workspace.file_project_paths(cx));