This commit is contained in:
Nathan Sobo 2023-08-03 17:03:39 -06:00
parent 3c938a7377
commit afcc0d621b
13 changed files with 300 additions and 262 deletions

View file

@ -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::<copilot::request::GetCompletions, _, _>(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()

View file

@ -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| {

View file

@ -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()

View file

@ -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::<Vec<_>>();
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)

View file

@ -130,12 +130,12 @@ pub trait BorrowAppContext {
}
pub trait BorrowWindowContext {
type Return<T>;
type Result<T>;
fn read_with<T, F>(&self, window_id: usize, f: F) -> Self::Return<T>
fn read_window_with<T, F>(&self, window_id: usize, f: F) -> Self::Result<T>
where
F: FnOnce(&WindowContext) -> T;
fn update<T, F>(&mut self, window_id: usize, f: F) -> Self::Return<T>
fn update_window<T, F>(&mut self, window_id: usize, f: F) -> Self::Result<T>
where
F: FnOnce(&mut WindowContext) -> T;
}
@ -458,6 +458,26 @@ impl BorrowAppContext for AsyncAppContext {
}
}
impl BorrowWindowContext for AsyncAppContext {
type Result<T> = Option<T>;
fn read_window_with<T, F>(&self, window_id: usize, f: F) -> Self::Result<T>
where
F: FnOnce(&WindowContext) -> T,
{
self.0.borrow().read_with(|cx| cx.read_window(window_id, f))
}
fn update_window<T, F>(&mut self, window_id: usize, f: F) -> Self::Result<T>
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<T> = Option<T>;
fn read_window_with<T, F>(&self, window_id: usize, f: F) -> Self::Result<T>
where
F: FnOnce(&WindowContext) -> T,
{
AppContext::read_window(self, window_id, f)
}
fn update_window<T, F>(&mut self, window_id: usize, f: F) -> Self::Result<T>
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<V> BorrowAppContext for ViewContext<'_, '_, V> {
}
impl<V> BorrowWindowContext for ViewContext<'_, '_, V> {
type Return<T> = T;
type Result<T> = T;
fn read_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
BorrowWindowContext::read_with(&*self.window_context, window_id, f)
fn read_window_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
BorrowWindowContext::read_window_with(&*self.window_context, window_id, f)
}
fn update<T, F: FnOnce(&mut WindowContext) -> T>(&mut self, window_id: usize, f: F) -> T {
BorrowWindowContext::update(&mut *self.window_context, window_id, f)
fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
&mut self,
window_id: usize,
f: F,
) -> T {
BorrowWindowContext::update_window(&mut *self.window_context, window_id, f)
}
}
@ -3467,14 +3509,18 @@ impl<V: View> BorrowAppContext for LayoutContext<'_, '_, '_, V> {
}
impl<V: View> BorrowWindowContext for LayoutContext<'_, '_, '_, V> {
type Return<T> = T;
type Result<T> = T;
fn read_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
BorrowWindowContext::read_with(&*self.view_context, window_id, f)
fn read_window_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
BorrowWindowContext::read_window_with(&*self.view_context, window_id, f)
}
fn update<T, F: FnOnce(&mut WindowContext) -> T>(&mut self, window_id: usize, f: F) -> T {
BorrowWindowContext::update(&mut *self.view_context, window_id, f)
fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
&mut self,
window_id: usize,
f: F,
) -> T {
BorrowWindowContext::update_window(&mut *self.view_context, window_id, f)
}
}
@ -3521,14 +3567,18 @@ impl<V: View> BorrowAppContext for EventContext<'_, '_, '_, V> {
}
impl<V: View> BorrowWindowContext for EventContext<'_, '_, '_, V> {
type Return<T> = T;
type Result<T> = T;
fn read_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
BorrowWindowContext::read_with(&*self.view_context, window_id, f)
fn read_window_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
BorrowWindowContext::read_window_with(&*self.view_context, window_id, f)
}
fn update<T, F: FnOnce(&mut WindowContext) -> T>(&mut self, window_id: usize, f: F) -> T {
BorrowWindowContext::update(&mut *self.view_context, window_id, f)
fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
&mut self,
window_id: usize,
f: F,
) -> T {
BorrowWindowContext::update_window(&mut *self.view_context, window_id, f)
}
}
@ -3830,32 +3880,16 @@ impl<V: View> WindowHandle<V> {
self.any_handle.id()
}
pub fn root(&self, cx: &impl BorrowAppContext) -> ViewHandle<V> {
pub fn root<C: BorrowWindowContext>(&self, cx: &C) -> C::Result<ViewHandle<V>> {
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<V> {
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<C, F, R>(&self, cx: &C, read: F) -> R
pub fn read_with<C, F, R>(&self, cx: &C, read: F) -> C::Result<R>
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<C, F, R>(&self, cx: &mut C, update: F) -> R
@ -3891,9 +3925,9 @@ impl<V: View> WindowHandle<V> {
root_view.read(cx)
}
pub fn read_root_with<C, F, R>(&self, cx: &C, read: F) -> R
pub fn read_root_with<C, F, R>(&self, cx: &C, read: F) -> C::Result<R>
where
C: BorrowAppContext,
C: BorrowWindowContext,
F: FnOnce(&V, &ViewContext<V>) -> R,
{
self.read_with(cx, |cx| {
@ -4021,25 +4055,25 @@ impl<T: View> ViewHandle<T> {
cx.read_view(self)
}
pub fn read_with<C, F, S>(&self, cx: &C, read: F) -> C::Return<S>
pub fn read_with<C, F, S>(&self, cx: &C, read: F) -> C::Result<S>
where
C: BorrowWindowContext,
F: FnOnce(&T, &ViewContext<T>) -> 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<C, F, S>(&self, cx: &mut C, update: F) -> C::Return<S>
pub fn update<C, F, S>(&self, cx: &mut C, update: F) -> C::Result<S>
where
C: BorrowWindowContext,
F: FnOnce(&mut T, &mut ViewContext<T>) -> 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<Cell<bool>>,
}
@ -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<AnyViewHandle>,
@ -5846,68 +5882,70 @@ mod tests {
impl_actions!(test, [Action]);
let 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.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 }
});
}
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!("{} 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));
}
});
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();
let window = cx.add_window(Default::default(), |_| ViewA { id: 1, child: None });
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, 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));
}
});
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.capture_action({
let actions = actions.clone();
move |view: &mut ViewA, _: &Action, cx| {
cx.propagate_action();
actions.borrow_mut().push(format!("{} capture", view.id));
}
});
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(|_| 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!(

View file

@ -406,16 +406,20 @@ impl BorrowAppContext for TestAppContext {
}
impl BorrowWindowContext for TestAppContext {
type Return<T> = T;
type Result<T> = T;
fn read_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
fn read_window_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
self.cx
.borrow()
.read_window(window_id, f)
.expect("window was closed")
}
fn update<T, F: FnOnce(&mut WindowContext) -> T>(&mut self, window_id: usize, f: F) -> T {
fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
&mut self,
window_id: usize,
f: F,
) -> T {
self.cx
.borrow_mut()
.update_window(window_id, f)

View file

@ -142,9 +142,9 @@ impl BorrowAppContext for WindowContext<'_> {
}
impl BorrowWindowContext for WindowContext<'_> {
type Return<T> = T;
type Result<T> = T;
fn read_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
fn read_window_with<T, F: FnOnce(&WindowContext) -> 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, F: FnOnce(&mut WindowContext) -> T>(&mut self, window_id: usize, f: F) -> T {
fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
&mut self,
window_id: usize,
f: F,
) -> T {
if self.window_id == window_id {
f(self)
} else {

View file

@ -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::notification::LogMessage>(lsp::LogMessageParams {
message: "hello from the server".into(),

View file

@ -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| {

View file

@ -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

View file

@ -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)
}

View file

@ -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?;
});
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;
}
// 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()
};
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,
)
},
)
});
// 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,

View file

@ -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));