WIP: Return WindowHandle<V: View> from AppContext::add_window (#2820)

Instead of returning a usize for the window id, I'm instead returning a
`WindowHandle<V: View>` where `V` is the type of the window's root view.
@as-cii helped me with a cool technique using generic associated types
where methods on `WindowHandle` can return either T or Option<T>
depending on the `BorrowWindowContext::Result` associated type.

Some example usage...

```rs
let window = cx.add_window(|cx| MyView::new(cx));
let my_view = window.root(cx); // If cx is TestAppContext, returns MyView. Otherwise returns Option<MyView>, because the window could be closed.
```


This isn't insanely beneficial on its own, but I think it will help
clean up our testing story. I'm planning on making `window` more useful
in tests for laying out elements, etc.

- [x] Rework tests that call `add_window` 😅 to expect only a window in
return.
- [x] Get tests passing
- [x] 🚬  test
This commit is contained in:
Nathan Sobo 2023-08-03 18:45:51 -06:00 committed by GitHub
commit d3c1966d96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 1174 additions and 896 deletions

View file

@ -495,8 +495,9 @@ impl TestClient {
// We use a workspace container so that we don't need to remove the window in order to
// drop the workspace and we can use a ViewHandle instead.
let (window_id, container) = cx.add_window(|_| WorkspaceContainer { workspace: None });
let workspace = cx.add_view(window_id, |cx| Workspace::test_new(project.clone(), cx));
let window = cx.add_window(|_| WorkspaceContainer { workspace: None });
let container = window.root(cx);
let workspace = window.add_view(cx, |cx| Workspace::test_new(project.clone(), cx));
container.update(cx, |container, cx| {
container.workspace = Some(workspace.downgrade());
cx.notify();

View file

@ -7,8 +7,7 @@ use client::{User, RECEIVE_TIMEOUT};
use collections::HashSet;
use editor::{
test::editor_test_context::EditorTestContext, ConfirmCodeAction, ConfirmCompletion,
ConfirmRename, Editor, ExcerptRange, MultiBuffer, Redo, Rename, ToOffset, ToggleCodeActions,
Undo,
ConfirmRename, Editor, ExcerptRange, MultiBuffer, Redo, Rename, ToggleCodeActions, Undo,
};
use fs::{repository::GitFileStatus, FakeFs, Fs as _, LineEnding, RemoveOptions};
use futures::StreamExt as _;
@ -1208,7 +1207,7 @@ async fn test_share_project(
cx_c: &mut TestAppContext,
) {
deterministic.forbid_parking();
let (window_b, _) = cx_b.add_window(|_| EmptyView);
let window_b = cx_b.add_window(|_| EmptyView);
let mut server = TestServer::start(&deterministic).await;
let client_a = server.create_client(cx_a, "user_a").await;
let client_b = server.create_client(cx_b, "user_b").await;
@ -1316,7 +1315,7 @@ async fn test_share_project(
.await
.unwrap();
let editor_b = cx_b.add_view(window_b, |cx| Editor::for_buffer(buffer_b, None, cx));
let editor_b = window_b.add_view(cx_b, |cx| Editor::for_buffer(buffer_b, None, cx));
// Client A sees client B's selection
deterministic.run_until_parked();
@ -1499,8 +1498,8 @@ async fn test_host_disconnect(
deterministic.run_until_parked();
assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared()));
let (window_id_b, workspace_b) =
cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
let window_b = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
let workspace_b = window_b.root(cx_b);
let editor_b = workspace_b
.update(cx_b, |workspace, cx| {
workspace.open_path((worktree_id, "b.txt"), None, true, cx)
@ -1509,9 +1508,7 @@ async fn test_host_disconnect(
.unwrap()
.downcast::<Editor>()
.unwrap();
assert!(cx_b
.read_window(window_id_b, |cx| editor_b.is_focused(cx))
.unwrap());
assert!(window_b.read_with(cx_b, |cx| editor_b.is_focused(cx)));
editor_b.update(cx_b, |editor, cx| editor.insert("X", cx));
assert!(cx_b.is_window_edited(workspace_b.window_id()));
@ -1525,7 +1522,7 @@ async fn test_host_disconnect(
assert!(worktree_a.read_with(cx_a, |tree, _| !tree.as_local().unwrap().is_shared()));
// Ensure client B's edited state is reset and that the whole window is blurred.
cx_b.read_window(window_id_b, |cx| {
window_b.read_with(cx_b, |cx| {
assert_eq!(cx.focused_view_id(), None);
});
assert!(!cx_b.is_window_edited(workspace_b.window_id()));
@ -3445,13 +3442,11 @@ async fn test_newline_above_or_below_does_not_move_guest_cursor(
.update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
.await
.unwrap();
let (window_a, _) = cx_a.add_window(|_| EmptyView);
let editor_a = cx_a.add_view(window_a, |cx| {
Editor::for_buffer(buffer_a, Some(project_a), cx)
});
let window_a = cx_a.add_window(|_| EmptyView);
let editor_a = window_a.add_view(cx_a, |cx| Editor::for_buffer(buffer_a, Some(project_a), cx));
let mut editor_cx_a = EditorTestContext {
cx: cx_a,
window_id: window_a,
window_id: window_a.window_id(),
editor: editor_a,
};
@ -3460,13 +3455,11 @@ 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 (window_b, _) = cx_b.add_window(|_| EmptyView);
let editor_b = cx_b.add_view(window_b, |cx| {
Editor::for_buffer(buffer_b, Some(project_b), cx)
});
let window_b = cx_b.add_window(|_| EmptyView);
let editor_b = window_b.add_view(cx_b, |cx| Editor::for_buffer(buffer_b, Some(project_b), cx));
let mut editor_cx_b = EditorTestContext {
cx: cx_b,
window_id: window_b,
window_id: window_b.window_id(),
editor: editor_b,
};
@ -4205,8 +4198,8 @@ async fn test_collaborating_with_completion(
.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
.await
.unwrap();
let (window_b, _) = cx_b.add_window(|_| EmptyView);
let editor_b = cx_b.add_view(window_b, |cx| {
let window_b = cx_b.add_window(|_| EmptyView);
let editor_b = window_b.add_view(cx_b, |cx| {
Editor::for_buffer(buffer_b.clone(), Some(project_b.clone()), cx)
});
@ -5316,7 +5309,8 @@ async fn test_collaborating_with_code_actions(
// Join the project as client B.
let project_b = client_b.build_remote_project(project_id, cx_b).await;
let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
let window_b = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
let workspace_b = window_b.root(cx_b);
let editor_b = workspace_b
.update(cx_b, |workspace, cx| {
workspace.open_path((worktree_id, "main.rs"), None, true, cx)
@ -5540,7 +5534,8 @@ async fn test_collaborating_with_renames(
.unwrap();
let project_b = client_b.build_remote_project(project_id, cx_b).await;
let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
let window_b = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
let workspace_b = window_b.root(cx_b);
let editor_b = workspace_b
.update(cx_b, |workspace, cx| {
workspace.open_path((worktree_id, "one.rs"), None, true, cx)
@ -5571,6 +5566,7 @@ async fn test_collaborating_with_renames(
.unwrap();
prepare_rename.await.unwrap();
editor_b.update(cx_b, |editor, cx| {
use editor::ToOffset;
let rename = editor.pending_rename().unwrap();
let buffer = editor.buffer().read(cx).snapshot(cx);
assert_eq!(
@ -7601,8 +7597,8 @@ async fn test_on_input_format_from_host_to_guest(
.update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
.await
.unwrap();
let (window_a, _) = cx_a.add_window(|_| EmptyView);
let editor_a = cx_a.add_view(window_a, |cx| {
let window_a = cx_a.add_window(|_| EmptyView);
let editor_a = window_a.add_view(cx_a, |cx| {
Editor::for_buffer(buffer_a, Some(project_a.clone()), cx)
});
@ -7730,8 +7726,8 @@ async fn test_on_input_format_from_guest_to_host(
.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
.await
.unwrap();
let (window_b, _) = cx_b.add_window(|_| EmptyView);
let editor_b = cx_b.add_view(window_b, |cx| {
let window_b = cx_b.add_window(|_| EmptyView);
let editor_b = window_b.add_view(cx_b, |cx| {
Editor::for_buffer(buffer_b, Some(project_b.clone()), cx)
});