diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index b1f0d26786..891c15580e 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -10056,76 +10056,76 @@ pub fn diagnostic_style( } } -// pub fn combine_syntax_and_fuzzy_match_highlights( -// text: &str, -// default_style: HighlightStyle, -// syntax_ranges: impl Iterator, HighlightStyle)>, -// match_indices: &[usize], -// ) -> Vec<(Range, HighlightStyle)> { -// let mut result = Vec::new(); -// let mut match_indices = match_indices.iter().copied().peekable(); +pub fn combine_syntax_and_fuzzy_match_highlights( + text: &str, + default_style: HighlightStyle, + syntax_ranges: impl Iterator, HighlightStyle)>, + match_indices: &[usize], +) -> Vec<(Range, HighlightStyle)> { + let mut result = Vec::new(); + let mut match_indices = match_indices.iter().copied().peekable(); -// for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())]) -// { -// syntax_highlight.weight = None; + for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())]) + { + syntax_highlight.font_weight = None; -// // Add highlights for any fuzzy match characters before the next -// // syntax highlight range. -// while let Some(&match_index) = match_indices.peek() { -// if match_index >= range.start { -// break; -// } -// match_indices.next(); -// let end_index = char_ix_after(match_index, text); -// let mut match_style = default_style; -// match_style.weight = Some(FontWeight::BOLD); -// result.push((match_index..end_index, match_style)); -// } + // Add highlights for any fuzzy match characters before the next + // syntax highlight range. + while let Some(&match_index) = match_indices.peek() { + if match_index >= range.start { + break; + } + match_indices.next(); + let end_index = char_ix_after(match_index, text); + let mut match_style = default_style; + match_style.font_weight = Some(FontWeight::BOLD); + result.push((match_index..end_index, match_style)); + } -// if range.start == usize::MAX { -// break; -// } + if range.start == usize::MAX { + break; + } -// // Add highlights for any fuzzy match characters within the -// // syntax highlight range. -// let mut offset = range.start; -// while let Some(&match_index) = match_indices.peek() { -// if match_index >= range.end { -// break; -// } + // Add highlights for any fuzzy match characters within the + // syntax highlight range. + let mut offset = range.start; + while let Some(&match_index) = match_indices.peek() { + if match_index >= range.end { + break; + } -// match_indices.next(); -// if match_index > offset { -// result.push((offset..match_index, syntax_highlight)); -// } + match_indices.next(); + if match_index > offset { + result.push((offset..match_index, syntax_highlight)); + } -// let mut end_index = char_ix_after(match_index, text); -// while let Some(&next_match_index) = match_indices.peek() { -// if next_match_index == end_index && next_match_index < range.end { -// end_index = char_ix_after(next_match_index, text); -// match_indices.next(); -// } else { -// break; -// } -// } + let mut end_index = char_ix_after(match_index, text); + while let Some(&next_match_index) = match_indices.peek() { + if next_match_index == end_index && next_match_index < range.end { + end_index = char_ix_after(next_match_index, text); + match_indices.next(); + } else { + break; + } + } -// let mut match_style = syntax_highlight; -// match_style.weight = Some(FontWeight::BOLD); -// result.push((match_index..end_index, match_style)); -// offset = end_index; -// } + let mut match_style = syntax_highlight; + match_style.font_weight = Some(FontWeight::BOLD); + result.push((match_index..end_index, match_style)); + offset = end_index; + } -// if offset < range.end { -// result.push((offset..range.end, syntax_highlight)); -// } -// } + if offset < range.end { + result.push((offset..range.end, syntax_highlight)); + } + } -// fn char_ix_after(ix: usize, text: &str) -> usize { -// ix + text[ix..].chars().next().unwrap().len_utf8() -// } + fn char_ix_after(ix: usize, text: &str) -> usize { + ix + text[ix..].chars().next().unwrap().len_utf8() + } -// result -// } + result +} // pub fn styled_runs_for_code_label<'a>( // label: &'a CodeLabel, diff --git a/crates/editor2/src/editor_tests.rs b/crates/editor2/src/editor_tests.rs index 22eb6b3a08..eccf0d6d20 100644 --- a/crates/editor2/src/editor_tests.rs +++ b/crates/editor2/src/editor_tests.rs @@ -50,7 +50,8 @@ fn test_edit_events(cx: &mut TestAppContext) { let editor1 = cx.add_window({ let events = events.clone(); |cx| { - cx.subscribe(cx.view(), move |_, _, event, _| { + let view = cx.view().clone(); + cx.subscribe(&view, move |_, _, event, _| { if matches!(event, Event::Edited | Event::BufferEdited) { events.borrow_mut().push(("editor1", event.clone())); } @@ -63,7 +64,7 @@ fn test_edit_events(cx: &mut TestAppContext) { let editor2 = cx.add_window({ let events = events.clone(); |cx| { - cx.subscribe(cx.view(), move |_, _, event, _| { + cx.subscribe(&cx.view().clone(), move |_, _, event, _| { if matches!(event, Event::Edited | Event::BufferEdited) { events.borrow_mut().push(("editor2", event.clone())); } @@ -156,7 +157,7 @@ fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) { let mut now = Instant::now(); let buffer = cx.build_model(|cx| language::Buffer::new(0, cx.entity_id().as_u64(), "123456")); - let group_interval = buffer.read_with(cx, |buffer, _| buffer.transaction_group_interval()); + let group_interval = buffer.update(cx, |buffer, _| buffer.transaction_group_interval()); let buffer = cx.build_model(|cx| MultiBuffer::singleton(buffer, cx)); let editor = cx.add_window(|cx| build_editor(buffer.clone(), cx)); @@ -496,10 +497,10 @@ fn test_clone(cx: &mut TestAppContext) { ); assert_set_eq!( cloned_editor - .read_with(cx, |editor, cx| editor.selections.ranges::(cx)) + .update(cx, |editor, cx| editor.selections.ranges::(cx)) .unwrap(), editor - .read_with(cx, |editor, cx| editor.selections.ranges(cx)) + .update(cx, |editor, cx| editor.selections.ranges(cx)) .unwrap() ); assert_set_eq!( @@ -523,7 +524,7 @@ async fn test_navigation_history(cx: &mut TestAppContext) { let project = Project::test(fs, [], cx).await; let workspace = cx.add_window(|cx| Workspace::test_new(project, cx)); let pane = workspace - .read_with(cx, |workspace, _| workspace.active_pane().clone()) + .update(cx, |workspace, _| workspace.active_pane().clone()) .unwrap(); workspace.update(cx, |v, cx| { @@ -1279,357 +1280,358 @@ fn test_prev_next_word_bounds_with_soft_wrap(cx: &mut TestAppContext) { }); } -#[gpui::test] -async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppContext) { - init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx).await; +//todo!(simulate_resize) +// #[gpui::test] +// async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppContext) { +// init_test(cx, |_| {}); +// let mut cx = EditorTestContext::new(cx).await; - let line_height = cx.editor(|editor, cx| editor.style(cx).text.line_height(cx.font_cache())); - let window = cx.window; - window.simulate_resize(gpui::Point::new(100., 4. * line_height), &mut cx); +// let line_height = cx.editor(|editor, cx| editor.style(cx).text.line_height(cx.font_cache())); +// let window = cx.window; +// window.simulate_resize(gpui::Point::new(100., 4. * line_height), &mut cx); - cx.set_state( - &r#"ˇone - two +// cx.set_state( +// &r#"ˇone +// two - three - fourˇ - five +// three +// fourˇ +// five - six"# - .unindent(), - ); +// six"# +// .unindent(), +// ); - cx.update_editor(|editor, cx| editor.move_to_end_of_paragraph(&MoveToEndOfParagraph, cx)); - cx.assert_editor_state( - &r#"one - two - ˇ - three - four - five - ˇ - six"# - .unindent(), - ); +// cx.update_editor(|editor, cx| editor.move_to_end_of_paragraph(&MoveToEndOfParagraph, cx)); +// cx.assert_editor_state( +// &r#"one +// two +// ˇ +// three +// four +// five +// ˇ +// six"# +// .unindent(), +// ); - cx.update_editor(|editor, cx| editor.move_to_end_of_paragraph(&MoveToEndOfParagraph, cx)); - cx.assert_editor_state( - &r#"one - two +// cx.update_editor(|editor, cx| editor.move_to_end_of_paragraph(&MoveToEndOfParagraph, cx)); +// cx.assert_editor_state( +// &r#"one +// two - three - four - five - ˇ - sixˇ"# - .unindent(), - ); +// three +// four +// five +// ˇ +// sixˇ"# +// .unindent(), +// ); - cx.update_editor(|editor, cx| editor.move_to_end_of_paragraph(&MoveToEndOfParagraph, cx)); - cx.assert_editor_state( - &r#"one - two +// cx.update_editor(|editor, cx| editor.move_to_end_of_paragraph(&MoveToEndOfParagraph, cx)); +// cx.assert_editor_state( +// &r#"one +// two - three - four - five +// three +// four +// five - sixˇ"# - .unindent(), - ); +// sixˇ"# +// .unindent(), +// ); - cx.update_editor(|editor, cx| editor.move_to_start_of_paragraph(&MoveToStartOfParagraph, cx)); - cx.assert_editor_state( - &r#"one - two +// cx.update_editor(|editor, cx| editor.move_to_start_of_paragraph(&MoveToStartOfParagraph, cx)); +// cx.assert_editor_state( +// &r#"one +// two - three - four - five - ˇ - six"# - .unindent(), - ); +// three +// four +// five +// ˇ +// six"# +// .unindent(), +// ); - cx.update_editor(|editor, cx| editor.move_to_start_of_paragraph(&MoveToStartOfParagraph, cx)); - cx.assert_editor_state( - &r#"one - two - ˇ - three - four - five +// cx.update_editor(|editor, cx| editor.move_to_start_of_paragraph(&MoveToStartOfParagraph, cx)); +// cx.assert_editor_state( +// &r#"one +// two +// ˇ +// three +// four +// five - six"# - .unindent(), - ); +// six"# +// .unindent(), +// ); - cx.update_editor(|editor, cx| editor.move_to_start_of_paragraph(&MoveToStartOfParagraph, cx)); - cx.assert_editor_state( - &r#"ˇone - two +// cx.update_editor(|editor, cx| editor.move_to_start_of_paragraph(&MoveToStartOfParagraph, cx)); +// cx.assert_editor_state( +// &r#"ˇone +// two - three - four - five +// three +// four +// five - six"# - .unindent(), - ); -} +// six"# +// .unindent(), +// ); +// } -#[gpui::test] -async fn test_scroll_page_up_page_down(cx: &mut gpui::TestAppContext) { - init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx).await; - let line_height = cx.editor(|editor, cx| editor.style(cx).text.line_height(cx.font_cache())); - let window = cx.window; - window.simulate_resize(Point::new(1000., 4. * line_height + 0.5), &mut cx); +// #[gpui::test] +// async fn test_scroll_page_up_page_down(cx: &mut gpui::TestAppContext) { +// init_test(cx, |_| {}); +// let mut cx = EditorTestContext::new(cx).await; +// let line_height = cx.editor(|editor, cx| editor.style(cx).text.line_height(cx.font_cache())); +// let window = cx.window; +// window.simulate_resize(Point::new(1000., 4. * line_height + 0.5), &mut cx); - cx.set_state( - &r#"ˇone - two - three - four - five - six - seven - eight - nine - ten - "#, - ); +// cx.set_state( +// &r#"ˇone +// two +// three +// four +// five +// six +// seven +// eight +// nine +// ten +// "#, +// ); - cx.update_editor(|editor, cx| { - assert_eq!( - editor.snapshot(cx).scroll_position(), - gpui::Point::new(0., 0.) - ); - editor.scroll_screen(&ScrollAmount::Page(1.), cx); - assert_eq!( - editor.snapshot(cx).scroll_position(), - gpui::Point::new(0., 3.) - ); - editor.scroll_screen(&ScrollAmount::Page(1.), cx); - assert_eq!( - editor.snapshot(cx).scroll_position(), - gpui::Point::new(0., 6.) - ); - editor.scroll_screen(&ScrollAmount::Page(-1.), cx); - assert_eq!( - editor.snapshot(cx).scroll_position(), - gpui::Point::new(0., 3.) - ); +// cx.update_editor(|editor, cx| { +// assert_eq!( +// editor.snapshot(cx).scroll_position(), +// gpui::Point::new(0., 0.) +// ); +// editor.scroll_screen(&ScrollAmount::Page(1.), cx); +// assert_eq!( +// editor.snapshot(cx).scroll_position(), +// gpui::Point::new(0., 3.) +// ); +// editor.scroll_screen(&ScrollAmount::Page(1.), cx); +// assert_eq!( +// editor.snapshot(cx).scroll_position(), +// gpui::Point::new(0., 6.) +// ); +// editor.scroll_screen(&ScrollAmount::Page(-1.), cx); +// assert_eq!( +// editor.snapshot(cx).scroll_position(), +// gpui::Point::new(0., 3.) +// ); - editor.scroll_screen(&ScrollAmount::Page(-0.5), cx); - assert_eq!( - editor.snapshot(cx).scroll_position(), - gpui::Point::new(0., 1.) - ); - editor.scroll_screen(&ScrollAmount::Page(0.5), cx); - assert_eq!( - editor.snapshot(cx).scroll_position(), - gpui::Point::new(0., 3.) - ); - }); -} +// editor.scroll_screen(&ScrollAmount::Page(-0.5), cx); +// assert_eq!( +// editor.snapshot(cx).scroll_position(), +// gpui::Point::new(0., 1.) +// ); +// editor.scroll_screen(&ScrollAmount::Page(0.5), cx); +// assert_eq!( +// editor.snapshot(cx).scroll_position(), +// gpui::Point::new(0., 3.) +// ); +// }); +// } -#[gpui::test] -async fn test_autoscroll(cx: &mut gpui::TestAppContext) { - init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx).await; +// #[gpui::test] +// async fn test_autoscroll(cx: &mut gpui::TestAppContext) { +// init_test(cx, |_| {}); +// let mut cx = EditorTestContext::new(cx).await; - let line_height = cx.update_editor(|editor, cx| { - editor.set_vertical_scroll_margin(2, cx); - editor.style(cx).text.line_height(cx.font_cache()) - }); +// let line_height = cx.update_editor(|editor, cx| { +// editor.set_vertical_scroll_margin(2, cx); +// editor.style(cx).text.line_height(cx.font_cache()) +// }); - let window = cx.window; - window.simulate_resize(gpui::Point::new(1000., 6.0 * line_height), &mut cx); +// let window = cx.window; +// window.simulate_resize(gpui::Point::new(1000., 6.0 * line_height), &mut cx); - cx.set_state( - &r#"ˇone - two - three - four - five - six - seven - eight - nine - ten - "#, - ); - cx.update_editor(|editor, cx| { - assert_eq!( - editor.snapshot(cx).scroll_position(), - gpui::Point::new(0., 0.0) - ); - }); +// cx.set_state( +// &r#"ˇone +// two +// three +// four +// five +// six +// seven +// eight +// nine +// ten +// "#, +// ); +// cx.update_editor(|editor, cx| { +// assert_eq!( +// editor.snapshot(cx).scroll_position(), +// gpui::Point::new(0., 0.0) +// ); +// }); - // Add a cursor below the visible area. Since both cursors cannot fit - // on screen, the editor autoscrolls to reveal the newest cursor, and - // allows the vertical scroll margin below that cursor. - cx.update_editor(|editor, cx| { - editor.change_selections(Some(Autoscroll::fit()), cx, |selections| { - selections.select_ranges([ - Point::new(0, 0)..Point::new(0, 0), - Point::new(6, 0)..Point::new(6, 0), - ]); - }) - }); - cx.update_editor(|editor, cx| { - assert_eq!( - editor.snapshot(cx).scroll_position(), - gpui::Point::new(0., 3.0) - ); - }); +// // Add a cursor below the visible area. Since both cursors cannot fit +// // on screen, the editor autoscrolls to reveal the newest cursor, and +// // allows the vertical scroll margin below that cursor. +// cx.update_editor(|editor, cx| { +// editor.change_selections(Some(Autoscroll::fit()), cx, |selections| { +// selections.select_ranges([ +// Point::new(0, 0)..Point::new(0, 0), +// Point::new(6, 0)..Point::new(6, 0), +// ]); +// }) +// }); +// cx.update_editor(|editor, cx| { +// assert_eq!( +// editor.snapshot(cx).scroll_position(), +// gpui::Point::new(0., 3.0) +// ); +// }); - // Move down. The editor cursor scrolls down to track the newest cursor. - cx.update_editor(|editor, cx| { - editor.move_down(&Default::default(), cx); - }); - cx.update_editor(|editor, cx| { - assert_eq!( - editor.snapshot(cx).scroll_position(), - gpui::Point::new(0., 4.0) - ); - }); +// // Move down. The editor cursor scrolls down to track the newest cursor. +// cx.update_editor(|editor, cx| { +// editor.move_down(&Default::default(), cx); +// }); +// cx.update_editor(|editor, cx| { +// assert_eq!( +// editor.snapshot(cx).scroll_position(), +// gpui::Point::new(0., 4.0) +// ); +// }); - // Add a cursor above the visible area. Since both cursors fit on screen, - // the editor scrolls to show both. - cx.update_editor(|editor, cx| { - editor.change_selections(Some(Autoscroll::fit()), cx, |selections| { - selections.select_ranges([ - Point::new(1, 0)..Point::new(1, 0), - Point::new(6, 0)..Point::new(6, 0), - ]); - }) - }); - cx.update_editor(|editor, cx| { - assert_eq!( - editor.snapshot(cx).scroll_position(), - gpui::Point::new(0., 1.0) - ); - }); -} +// // Add a cursor above the visible area. Since both cursors fit on screen, +// // the editor scrolls to show both. +// cx.update_editor(|editor, cx| { +// editor.change_selections(Some(Autoscroll::fit()), cx, |selections| { +// selections.select_ranges([ +// Point::new(1, 0)..Point::new(1, 0), +// Point::new(6, 0)..Point::new(6, 0), +// ]); +// }) +// }); +// cx.update_editor(|editor, cx| { +// assert_eq!( +// editor.snapshot(cx).scroll_position(), +// gpui::Point::new(0., 1.0) +// ); +// }); +// } -#[gpui::test] -async fn test_move_page_up_page_down(cx: &mut gpui::TestAppContext) { - init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx).await; +// #[gpui::test] +// async fn test_move_page_up_page_down(cx: &mut gpui::TestAppContext) { +// init_test(cx, |_| {}); +// let mut cx = EditorTestContext::new(cx).await; - let line_height = cx.editor(|editor, cx| editor.style(cx).text.line_height(cx.font_cache())); - let window = cx.window; - window.simulate_resize(gpui::Point::new(100., 4. * line_height), &mut cx); +// let line_height = cx.editor(|editor, cx| editor.style(cx).text.line_height(cx.font_cache())); +// let window = cx.window; +// window.simulate_resize(gpui::Point::new(100., 4. * line_height), &mut cx); - cx.set_state( - &r#" - ˇone - two - threeˇ - four - five - six - seven - eight - nine - ten - "# - .unindent(), - ); +// cx.set_state( +// &r#" +// ˇone +// two +// threeˇ +// four +// five +// six +// seven +// eight +// nine +// ten +// "# +// .unindent(), +// ); - cx.update_editor(|editor, cx| editor.move_page_down(&MovePageDown::default(), cx)); - cx.assert_editor_state( - &r#" - one - two - three - ˇfour - five - sixˇ - seven - eight - nine - ten - "# - .unindent(), - ); +// cx.update_editor(|editor, cx| editor.move_page_down(&MovePageDown::default(), cx)); +// cx.assert_editor_state( +// &r#" +// one +// two +// three +// ˇfour +// five +// sixˇ +// seven +// eight +// nine +// ten +// "# +// .unindent(), +// ); - cx.update_editor(|editor, cx| editor.move_page_down(&MovePageDown::default(), cx)); - cx.assert_editor_state( - &r#" - one - two - three - four - five - six - ˇseven - eight - nineˇ - ten - "# - .unindent(), - ); +// cx.update_editor(|editor, cx| editor.move_page_down(&MovePageDown::default(), cx)); +// cx.assert_editor_state( +// &r#" +// one +// two +// three +// four +// five +// six +// ˇseven +// eight +// nineˇ +// ten +// "# +// .unindent(), +// ); - cx.update_editor(|editor, cx| editor.move_page_up(&MovePageUp::default(), cx)); - cx.assert_editor_state( - &r#" - one - two - three - ˇfour - five - sixˇ - seven - eight - nine - ten - "# - .unindent(), - ); +// cx.update_editor(|editor, cx| editor.move_page_up(&MovePageUp::default(), cx)); +// cx.assert_editor_state( +// &r#" +// one +// two +// three +// ˇfour +// five +// sixˇ +// seven +// eight +// nine +// ten +// "# +// .unindent(), +// ); - cx.update_editor(|editor, cx| editor.move_page_up(&MovePageUp::default(), cx)); - cx.assert_editor_state( - &r#" - ˇone - two - threeˇ - four - five - six - seven - eight - nine - ten - "# - .unindent(), - ); +// cx.update_editor(|editor, cx| editor.move_page_up(&MovePageUp::default(), cx)); +// cx.assert_editor_state( +// &r#" +// ˇone +// two +// threeˇ +// four +// five +// six +// seven +// eight +// nine +// ten +// "# +// .unindent(), +// ); - // Test select collapsing - cx.update_editor(|editor, cx| { - editor.move_page_down(&MovePageDown::default(), cx); - editor.move_page_down(&MovePageDown::default(), cx); - editor.move_page_down(&MovePageDown::default(), cx); - }); - cx.assert_editor_state( - &r#" - one - two - three - four - five - six - seven - eight - nine - ˇten - ˇ"# - .unindent(), - ); -} +// // Test select collapsing +// cx.update_editor(|editor, cx| { +// editor.move_page_down(&MovePageDown::default(), cx); +// editor.move_page_down(&MovePageDown::default(), cx); +// editor.move_page_down(&MovePageDown::default(), cx); +// }); +// cx.assert_editor_state( +// &r#" +// one +// two +// three +// four +// five +// six +// seven +// eight +// nine +// ˇten +// ˇ"# +// .unindent(), +// ); +// } #[gpui::test] async fn test_delete_to_beginning_of_line(cx: &mut gpui::TestAppContext) { @@ -3042,7 +3044,7 @@ fn test_move_line_up_down_with_blocks(cx: &mut TestAppContext) { position: snapshot.anchor_after(Point::new(2, 0)), disposition: BlockDisposition::Below, height: 1, - render: Arc::new(|_| Empty::new().into_any()), + render: Arc::new(|_| div().render()), }], Some(Autoscroll::fit()), cx, @@ -3148,201 +3150,202 @@ fn test_transpose(cx: &mut TestAppContext) { }); } -#[gpui::test] -async fn test_clipboard(cx: &mut gpui::TestAppContext) { - init_test(cx, |_| {}); +//todo!(clipboard) +// #[gpui::test] +// async fn test_clipboard(cx: &mut gpui::TestAppContext) { +// init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx).await; +// let mut cx = EditorTestContext::new(cx).await; - cx.set_state("«one✅ ˇ»two «three ˇ»four «five ˇ»six "); - cx.update_editor(|e, cx| e.cut(&Cut, cx)); - cx.assert_editor_state("ˇtwo ˇfour ˇsix "); +// cx.set_state("«one✅ ˇ»two «three ˇ»four «five ˇ»six "); +// cx.update_editor(|e, cx| e.cut(&Cut, cx)); +// cx.assert_editor_state("ˇtwo ˇfour ˇsix "); - // Paste with three cursors. Each cursor pastes one slice of the clipboard text. - cx.set_state("two ˇfour ˇsix ˇ"); - cx.update_editor(|e, cx| e.paste(&Paste, cx)); - cx.assert_editor_state("two one✅ ˇfour three ˇsix five ˇ"); +// // Paste with three cursors. Each cursor pastes one slice of the clipboard text. +// cx.set_state("two ˇfour ˇsix ˇ"); +// cx.update_editor(|e, cx| e.paste(&Paste, cx)); +// cx.assert_editor_state("two one✅ ˇfour three ˇsix five ˇ"); - // Paste again but with only two cursors. Since the number of cursors doesn't - // match the number of slices in the clipboard, the entire clipboard text - // is pasted at each cursor. - cx.set_state("ˇtwo one✅ four three six five ˇ"); - cx.update_editor(|e, cx| { - e.handle_input("( ", cx); - e.paste(&Paste, cx); - e.handle_input(") ", cx); - }); - cx.assert_editor_state( - &([ - "( one✅ ", - "three ", - "five ) ˇtwo one✅ four three six five ( one✅ ", - "three ", - "five ) ˇ", - ] - .join("\n")), - ); +// // Paste again but with only two cursors. Since the number of cursors doesn't +// // match the number of slices in the clipboard, the entire clipboard text +// // is pasted at each cursor. +// cx.set_state("ˇtwo one✅ four three six five ˇ"); +// cx.update_editor(|e, cx| { +// e.handle_input("( ", cx); +// e.paste(&Paste, cx); +// e.handle_input(") ", cx); +// }); +// cx.assert_editor_state( +// &([ +// "( one✅ ", +// "three ", +// "five ) ˇtwo one✅ four three six five ( one✅ ", +// "three ", +// "five ) ˇ", +// ] +// .join("\n")), +// ); - // Cut with three selections, one of which is full-line. - cx.set_state(indoc! {" - 1«2ˇ»3 - 4ˇ567 - «8ˇ»9"}); - cx.update_editor(|e, cx| e.cut(&Cut, cx)); - cx.assert_editor_state(indoc! {" - 1ˇ3 - ˇ9"}); +// // Cut with three selections, one of which is full-line. +// cx.set_state(indoc! {" +// 1«2ˇ»3 +// 4ˇ567 +// «8ˇ»9"}); +// cx.update_editor(|e, cx| e.cut(&Cut, cx)); +// cx.assert_editor_state(indoc! {" +// 1ˇ3 +// ˇ9"}); - // Paste with three selections, noticing how the copied selection that was full-line - // gets inserted before the second cursor. - cx.set_state(indoc! {" - 1ˇ3 - 9ˇ - «oˇ»ne"}); - cx.update_editor(|e, cx| e.paste(&Paste, cx)); - cx.assert_editor_state(indoc! {" - 12ˇ3 - 4567 - 9ˇ - 8ˇne"}); +// // Paste with three selections, noticing how the copied selection that was full-line +// // gets inserted before the second cursor. +// cx.set_state(indoc! {" +// 1ˇ3 +// 9ˇ +// «oˇ»ne"}); +// cx.update_editor(|e, cx| e.paste(&Paste, cx)); +// cx.assert_editor_state(indoc! {" +// 12ˇ3 +// 4567 +// 9ˇ +// 8ˇne"}); - // Copy with a single cursor only, which writes the whole line into the clipboard. - cx.set_state(indoc! {" - The quick brown - fox juˇmps over - the lazy dog"}); - cx.update_editor(|e, cx| e.copy(&Copy, cx)); - cx.cx.assert_clipboard_content(Some("fox jumps over\n")); +// // Copy with a single cursor only, which writes the whole line into the clipboard. +// cx.set_state(indoc! {" +// The quick brown +// fox juˇmps over +// the lazy dog"}); +// cx.update_editor(|e, cx| e.copy(&Copy, cx)); +// cx.cx.assert_clipboard_content(Some("fox jumps over\n")); - // Paste with three selections, noticing how the copied full-line selection is inserted - // before the empty selections but replaces the selection that is non-empty. - cx.set_state(indoc! {" - Tˇhe quick brown - «foˇ»x jumps over - tˇhe lazy dog"}); - cx.update_editor(|e, cx| e.paste(&Paste, cx)); - cx.assert_editor_state(indoc! {" - fox jumps over - Tˇhe quick brown - fox jumps over - ˇx jumps over - fox jumps over - tˇhe lazy dog"}); -} +// // Paste with three selections, noticing how the copied full-line selection is inserted +// // before the empty selections but replaces the selection that is non-empty. +// cx.set_state(indoc! {" +// Tˇhe quick brown +// «foˇ»x jumps over +// tˇhe lazy dog"}); +// cx.update_editor(|e, cx| e.paste(&Paste, cx)); +// cx.assert_editor_state(indoc! {" +// fox jumps over +// Tˇhe quick brown +// fox jumps over +// ˇx jumps over +// fox jumps over +// tˇhe lazy dog"}); +// } -#[gpui::test] -async fn test_paste_multiline(cx: &mut gpui::TestAppContext) { - init_test(cx, |_| {}); +// #[gpui::test] +// async fn test_paste_multiline(cx: &mut gpui::TestAppContext) { +// init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx).await; - let language = Arc::new(Language::new( - LanguageConfig::default(), - Some(tree_sitter_rust::language()), - )); - cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx)); +// let mut cx = EditorTestContext::new(cx).await; +// let language = Arc::new(Language::new( +// LanguageConfig::default(), +// Some(tree_sitter_rust::language()), +// )); +// cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx)); - // Cut an indented block, without the leading whitespace. - cx.set_state(indoc! {" - const a: B = ( - c(), - «d( - e, - f - )ˇ» - ); - "}); - cx.update_editor(|e, cx| e.cut(&Cut, cx)); - cx.assert_editor_state(indoc! {" - const a: B = ( - c(), - ˇ - ); - "}); +// // Cut an indented block, without the leading whitespace. +// cx.set_state(indoc! {" +// const a: B = ( +// c(), +// «d( +// e, +// f +// )ˇ» +// ); +// "}); +// cx.update_editor(|e, cx| e.cut(&Cut, cx)); +// cx.assert_editor_state(indoc! {" +// const a: B = ( +// c(), +// ˇ +// ); +// "}); - // Paste it at the same position. - cx.update_editor(|e, cx| e.paste(&Paste, cx)); - cx.assert_editor_state(indoc! {" - const a: B = ( - c(), - d( - e, - f - )ˇ - ); - "}); +// // Paste it at the same position. +// cx.update_editor(|e, cx| e.paste(&Paste, cx)); +// cx.assert_editor_state(indoc! {" +// const a: B = ( +// c(), +// d( +// e, +// f +// )ˇ +// ); +// "}); - // Paste it at a line with a lower indent level. - cx.set_state(indoc! {" - ˇ - const a: B = ( - c(), - ); - "}); - cx.update_editor(|e, cx| e.paste(&Paste, cx)); - cx.assert_editor_state(indoc! {" - d( - e, - f - )ˇ - const a: B = ( - c(), - ); - "}); +// // Paste it at a line with a lower indent level. +// cx.set_state(indoc! {" +// ˇ +// const a: B = ( +// c(), +// ); +// "}); +// cx.update_editor(|e, cx| e.paste(&Paste, cx)); +// cx.assert_editor_state(indoc! {" +// d( +// e, +// f +// )ˇ +// const a: B = ( +// c(), +// ); +// "}); - // Cut an indented block, with the leading whitespace. - cx.set_state(indoc! {" - const a: B = ( - c(), - « d( - e, - f - ) - ˇ»); - "}); - cx.update_editor(|e, cx| e.cut(&Cut, cx)); - cx.assert_editor_state(indoc! {" - const a: B = ( - c(), - ˇ); - "}); +// // Cut an indented block, with the leading whitespace. +// cx.set_state(indoc! {" +// const a: B = ( +// c(), +// « d( +// e, +// f +// ) +// ˇ»); +// "}); +// cx.update_editor(|e, cx| e.cut(&Cut, cx)); +// cx.assert_editor_state(indoc! {" +// const a: B = ( +// c(), +// ˇ); +// "}); - // Paste it at the same position. - cx.update_editor(|e, cx| e.paste(&Paste, cx)); - cx.assert_editor_state(indoc! {" - const a: B = ( - c(), - d( - e, - f - ) - ˇ); - "}); +// // Paste it at the same position. +// cx.update_editor(|e, cx| e.paste(&Paste, cx)); +// cx.assert_editor_state(indoc! {" +// const a: B = ( +// c(), +// d( +// e, +// f +// ) +// ˇ); +// "}); - // Paste it at a line with a higher indent level. - cx.set_state(indoc! {" - const a: B = ( - c(), - d( - e, - fˇ - ) - ); - "}); - cx.update_editor(|e, cx| e.paste(&Paste, cx)); - cx.assert_editor_state(indoc! {" - const a: B = ( - c(), - d( - e, - f d( - e, - f - ) - ˇ - ) - ); - "}); -} +// // Paste it at a line with a higher indent level. +// cx.set_state(indoc! {" +// const a: B = ( +// c(), +// d( +// e, +// fˇ +// ) +// ); +// "}); +// cx.update_editor(|e, cx| e.paste(&Paste, cx)); +// cx.assert_editor_state(indoc! {" +// const a: B = ( +// c(), +// d( +// e, +// f d( +// e, +// f +// ) +// ˇ +// ) +// ); +// "}); +// } #[gpui::test] fn test_select_all(cx: &mut TestAppContext) { @@ -3785,11 +3788,12 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { Buffer::new(0, cx.entity_id().as_u64(), text).with_language(language, cx) }); let buffer = cx.build_model(|cx| MultiBuffer::singleton(buffer, cx)); - let view = cx.add_window(|cx| build_editor(buffer, cx)); - view.condition(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) + let (view, mut cx) = cx.add_window_view(|cx| build_editor(buffer, cx)); + + view.condition::(&cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) .await; - view.update(cx, |view, cx| { + view.update(&mut cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), @@ -3800,8 +3804,7 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx); }); assert_eq!( - view.update(cx, |view, cx| { view.selections.display_ranges(cx) }) - .unwrap(), + view.update(&mut cx, |view, cx| { view.selections.display_ranges(cx) }), &[ DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27), DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), @@ -3809,55 +3812,50 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { ] ); - view.update(cx, |view, cx| { + view.update(&mut cx, |view, cx| { view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx); }); assert_eq!( - view.update(cx, |view, cx| view.selections.display_ranges(cx)) - .unwrap(), + view.update(&mut cx, |view, cx| view.selections.display_ranges(cx)), &[ DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0), ] ); - view.update(cx, |view, cx| { + view.update(&mut cx, |view, cx| { view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx); }); assert_eq!( - view.update(cx, |view, cx| view.selections.display_ranges(cx)) - .unwrap(), + view.update(&mut cx, |view, cx| view.selections.display_ranges(cx)), &[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 0)] ); // Trying to expand the selected syntax node one more time has no effect. - view.update(cx, |view, cx| { + view.update(&mut cx, |view, cx| { view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx); }); assert_eq!( - view.update(cx, |view, cx| view.selections.display_ranges(cx)) - .unwrap(), + view.update(&mut cx, |view, cx| view.selections.display_ranges(cx)), &[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 0)] ); - view.update(cx, |view, cx| { + view.update(&mut cx, |view, cx| { view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx); }); assert_eq!( - view.update(cx, |view, cx| view.selections.display_ranges(cx)) - .unwrap(), + view.update(&mut cx, |view, cx| view.selections.display_ranges(cx)), &[ DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0), ] ); - view.update(cx, |view, cx| { + view.update(&mut cx, |view, cx| { view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx); }); assert_eq!( - view.update(cx, |view, cx| view.selections.display_ranges(cx)) - .unwrap(), + view.update(&mut cx, |view, cx| view.selections.display_ranges(cx)), &[ DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27), DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), @@ -3865,12 +3863,11 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { ] ); - view.update(cx, |view, cx| { + view.update(&mut cx, |view, cx| { view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx); }); assert_eq!( - view.update(cx, |view, cx| view.selections.display_ranges(cx)) - .unwrap(), + view.update(&mut cx, |view, cx| view.selections.display_ranges(cx)), &[ DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12), @@ -3879,12 +3876,11 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { ); // Trying to shrink the selected syntax node one more time has no effect. - view.update(cx, |view, cx| { + view.update(&mut cx, |view, cx| { view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx); }); assert_eq!( - view.update(cx, |view, cx| view.selections.display_ranges(cx)) - .unwrap(), + view.update(&mut cx, |view, cx| view.selections.display_ranges(cx)), &[ DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12), @@ -3894,7 +3890,7 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { // Ensure that we keep expanding the selection if the larger selection starts or ends within // a fold. - view.update(cx, |view, cx| { + view.update(&mut cx, |view, cx| { view.fold_ranges( vec![ Point::new(0, 21)..Point::new(0, 24), @@ -3906,8 +3902,7 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx); }); assert_eq!( - view.update(cx, |view, cx| view.selections.display_ranges(cx)) - .unwrap(), + view.update(&mut cx, |view, cx| view.selections.display_ranges(cx)), &[ DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), @@ -3959,9 +3954,10 @@ async fn test_autoindent_selections(cx: &mut gpui::TestAppContext) { Buffer::new(0, cx.entity_id().as_u64(), text).with_language(language, cx) }); let buffer = cx.build_model(|cx| MultiBuffer::singleton(buffer, cx)); - let editor = cx.add_window(|cx| build_editor(buffer, cx)); + let (editor, mut cx) = cx.add_window_view(|cx| build_editor(buffer, cx)); + let cx = &mut cx; editor - .condition(cx, |editor, cx| !editor.buffer.read(cx).is_parsing(cx)) + .condition::(cx, |editor, cx| !editor.buffer.read(cx).is_parsing(cx)) .await; editor.update(cx, |editor, cx| { @@ -4524,8 +4520,9 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { Buffer::new(0, cx.entity_id().as_u64(), text).with_language(language, cx) }); let buffer = cx.build_model(|cx| MultiBuffer::singleton(buffer, cx)); - let view = cx.add_window(|cx| build_editor(buffer, cx)); - view.condition(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) + let (view, mut cx) = cx.add_window_view(|cx| build_editor(buffer, cx)); + let cx = &mut cx; + view.condition::(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) .await; view.update(cx, |view, cx| { @@ -4674,9 +4671,10 @@ async fn test_delete_autoclose_pair(cx: &mut gpui::TestAppContext) { Buffer::new(0, cx.entity_id().as_u64(), text).with_language(language, cx) }); let buffer = cx.build_model(|cx| MultiBuffer::singleton(buffer, cx)); - let editor = cx.add_window(|cx| build_editor(buffer, cx)); + let (editor, mut cx) = cx.add_window_view(|cx| build_editor(buffer, cx)); + let cx = &mut cx; editor - .condition(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) + .condition::(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) .await; editor.update(cx, |editor, cx| { @@ -4764,7 +4762,8 @@ 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)); + let (editor, mut cx) = cx.add_window_view(|cx| build_editor(buffer, cx)); + let cx = &mut cx; editor.update(cx, |editor, cx| { let snippet = Snippet::parse("f(${1:one}, ${2:two}, ${1:three})$0").unwrap(); @@ -4894,7 +4893,8 @@ async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) { let fake_server = fake_servers.next().await.unwrap(); let buffer = cx.build_model(|cx| MultiBuffer::singleton(buffer, cx)); - let editor = cx.add_window(|cx| build_editor(buffer, cx)); + let (editor, mut cx) = cx.add_window_view(|cx| build_editor(buffer, cx)); + let cx = &mut cx; editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx)); assert!(cx.read(|cx| editor.is_dirty(cx))); @@ -4916,9 +4916,10 @@ async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) { .next() .await; cx.executor().start_waiting(); - save.await.unwrap(); + let x = save.await; + assert_eq!( - editor.read_with(cx, |editor, cx| editor.text(cx)).unwrap(), + editor.update(cx, |editor, cx| editor.text(cx)), "one, two\nthree\n" ); assert!(!cx.read(|cx| editor.is_dirty(cx))); @@ -4940,9 +4941,9 @@ async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) { .unwrap(); cx.executor().advance_clock(super::FORMAT_TIMEOUT); cx.executor().start_waiting(); - save.await.unwrap(); + save.await; assert_eq!( - editor.read_with(cx, |editor, cx| editor.text(cx)).unwrap(), + editor.update(cx, |editor, cx| editor.text(cx)), "one\ntwo\nthree\n" ); assert!(!cx.read(|cx| editor.is_dirty(cx))); @@ -4973,7 +4974,7 @@ async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) { .next() .await; cx.executor().start_waiting(); - save.await.unwrap(); + save.await; } #[gpui::test] @@ -5012,7 +5013,8 @@ async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) { let fake_server = fake_servers.next().await.unwrap(); let buffer = cx.build_model(|cx| MultiBuffer::singleton(buffer, cx)); - let editor = cx.add_window(|cx| build_editor(buffer, cx)); + let (editor, mut cx) = cx.add_window_view(|cx| build_editor(buffer, cx)); + let cx = &mut cx; editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx)); assert!(cx.read(|cx| editor.is_dirty(cx))); @@ -5034,9 +5036,9 @@ async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) { .next() .await; cx.executor().start_waiting(); - save.await.unwrap(); + save.await; assert_eq!( - editor.read_with(cx, |editor, cx| editor.text(cx)).unwrap(), + editor.update(cx, |editor, cx| editor.text(cx)), "one, two\nthree\n" ); assert!(!cx.read(|cx| editor.is_dirty(cx))); @@ -5060,9 +5062,9 @@ async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) { .unwrap(); cx.executor().advance_clock(super::FORMAT_TIMEOUT); cx.executor().start_waiting(); - save.await.unwrap(); + save.await; assert_eq!( - editor.read_with(cx, |editor, cx| editor.text(cx)).unwrap(), + editor.update(cx, |editor, cx| editor.text(cx)), "one\ntwo\nthree\n" ); assert!(!cx.read(|cx| editor.is_dirty(cx))); @@ -5093,7 +5095,7 @@ async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) { .next() .await; cx.executor().start_waiting(); - save.await.unwrap(); + save.await; } #[gpui::test] @@ -5139,7 +5141,8 @@ async fn test_document_format_manual_trigger(cx: &mut gpui::TestAppContext) { let fake_server = fake_servers.next().await.unwrap(); let buffer = cx.build_model(|cx| MultiBuffer::singleton(buffer, cx)); - let editor = cx.add_window(|cx| build_editor(buffer, cx)); + let (editor, mut cx) = cx.add_window_view(|cx| build_editor(buffer, cx)); + let cx = &mut cx; editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx)); let format = editor @@ -5162,9 +5165,9 @@ async fn test_document_format_manual_trigger(cx: &mut gpui::TestAppContext) { .next() .await; cx.executor().start_waiting(); - format.await.unwrap(); + format.await; assert_eq!( - editor.read_with(cx, |editor, cx| editor.text(cx)).unwrap(), + editor.update(cx, |editor, cx| editor.text(cx)), "one, two\nthree\n" ); @@ -5185,9 +5188,9 @@ async fn test_document_format_manual_trigger(cx: &mut gpui::TestAppContext) { .unwrap(); cx.executor().advance_clock(super::FORMAT_TIMEOUT); cx.executor().start_waiting(); - format.await.unwrap(); + format.await; assert_eq!( - editor.read_with(cx, |editor, cx| editor.text(cx)).unwrap(), + editor.update(cx, |editor, cx| editor.text(cx)), "one\ntwo\nthree\n" ); } @@ -5213,7 +5216,7 @@ async fn test_concurrent_format_requests(cx: &mut gpui::TestAppContext) { // a newline and an indent before the `.` cx.lsp .handle_request::(move |_, cx| { - let executor = cx.background_executor(); + let executor = cx.background_executor().clone(); async move { executor.timer(Duration::from_millis(100)).await; Ok(Some(vec![lsp::TextEdit { @@ -5366,177 +5369,178 @@ async fn test_strip_whitespace_and_format_via_lsp(cx: &mut gpui::TestAppContext) ); } -#[gpui::test] -async fn test_completion(cx: &mut gpui::TestAppContext) { - init_test(cx, |_| {}); +//todo!(completion) +// #[gpui::test] +// async fn test_completion(cx: &mut gpui::TestAppContext) { +// init_test(cx, |_| {}); - let mut cx = EditorLspTestContext::new_rust( - lsp::ServerCapabilities { - completion_provider: Some(lsp::CompletionOptions { - trigger_characters: Some(vec![".".to_string(), ":".to_string()]), - resolve_provider: Some(true), - ..Default::default() - }), - ..Default::default() - }, - cx, - ) - .await; +// let mut cx = EditorLspTestContext::new_rust( +// lsp::ServerCapabilities { +// completion_provider: Some(lsp::CompletionOptions { +// trigger_characters: Some(vec![".".to_string(), ":".to_string()]), +// resolve_provider: Some(true), +// ..Default::default() +// }), +// ..Default::default() +// }, +// cx, +// ) +// .await; - cx.set_state(indoc! {" - oneˇ - two - three - "}); - cx.simulate_keystroke("."); - handle_completion_request( - &mut cx, - indoc! {" - one.|<> - two - three - "}, - vec!["first_completion", "second_completion"], - ) - .await; - cx.condition(|editor, _| editor.context_menu_visible()) - .await; - let apply_additional_edits = cx.update_editor(|editor, cx| { - editor.context_menu_next(&Default::default(), cx); - editor - .confirm_completion(&ConfirmCompletion::default(), cx) - .unwrap() - }); - cx.assert_editor_state(indoc! {" - one.second_completionˇ - two - three - "}); +// cx.set_state(indoc! {" +// oneˇ +// two +// three +// "}); +// cx.simulate_keystroke("."); +// handle_completion_request( +// &mut cx, +// indoc! {" +// one.|<> +// two +// three +// "}, +// vec!["first_completion", "second_completion"], +// ) +// .await; +// cx.condition(|editor, _| editor.context_menu_visible()) +// .await; +// let apply_additional_edits = cx.update_editor(|editor, cx| { +// editor.context_menu_next(&Default::default(), cx); +// editor +// .confirm_completion(&ConfirmCompletion::default(), cx) +// .unwrap() +// }); +// cx.assert_editor_state(indoc! {" +// one.second_completionˇ +// two +// three +// "}); - handle_resolve_completion_request( - &mut cx, - Some(vec![ - ( - //This overlaps with the primary completion edit which is - //misbehavior from the LSP spec, test that we filter it out - indoc! {" - one.second_ˇcompletion - two - threeˇ - "}, - "overlapping additional edit", - ), - ( - indoc! {" - one.second_completion - two - threeˇ - "}, - "\nadditional edit", - ), - ]), - ) - .await; - apply_additional_edits.await.unwrap(); - cx.assert_editor_state(indoc! {" - one.second_completionˇ - two - three - additional edit - "}); +// handle_resolve_completion_request( +// &mut cx, +// Some(vec![ +// ( +// //This overlaps with the primary completion edit which is +// //misbehavior from the LSP spec, test that we filter it out +// indoc! {" +// one.second_ˇcompletion +// two +// threeˇ +// "}, +// "overlapping additional edit", +// ), +// ( +// indoc! {" +// one.second_completion +// two +// threeˇ +// "}, +// "\nadditional edit", +// ), +// ]), +// ) +// .await; +// apply_additional_edits.await.unwrap(); +// cx.assert_editor_state(indoc! {" +// one.second_completionˇ +// two +// three +// additional edit +// "}); - cx.set_state(indoc! {" - one.second_completion - twoˇ - threeˇ - additional edit - "}); - cx.simulate_keystroke(" "); - assert!(cx.editor(|e, _| e.context_menu.read().is_none())); - cx.simulate_keystroke("s"); - assert!(cx.editor(|e, _| e.context_menu.read().is_none())); +// cx.set_state(indoc! {" +// one.second_completion +// twoˇ +// threeˇ +// additional edit +// "}); +// cx.simulate_keystroke(" "); +// assert!(cx.editor(|e, _| e.context_menu.read().is_none())); +// cx.simulate_keystroke("s"); +// assert!(cx.editor(|e, _| e.context_menu.read().is_none())); - cx.assert_editor_state(indoc! {" - one.second_completion - two sˇ - three sˇ - additional edit - "}); - handle_completion_request( - &mut cx, - indoc! {" - one.second_completion - two s - three - additional edit - "}, - vec!["fourth_completion", "fifth_completion", "sixth_completion"], - ) - .await; - cx.condition(|editor, _| editor.context_menu_visible()) - .await; +// cx.assert_editor_state(indoc! {" +// one.second_completion +// two sˇ +// three sˇ +// additional edit +// "}); +// handle_completion_request( +// &mut cx, +// indoc! {" +// one.second_completion +// two s +// three +// additional edit +// "}, +// vec!["fourth_completion", "fifth_completion", "sixth_completion"], +// ) +// .await; +// cx.condition(|editor, _| editor.context_menu_visible()) +// .await; - cx.simulate_keystroke("i"); +// cx.simulate_keystroke("i"); - handle_completion_request( - &mut cx, - indoc! {" - one.second_completion - two si - three - additional edit - "}, - vec!["fourth_completion", "fifth_completion", "sixth_completion"], - ) - .await; - cx.condition(|editor, _| editor.context_menu_visible()) - .await; +// handle_completion_request( +// &mut cx, +// indoc! {" +// one.second_completion +// two si +// three +// additional edit +// "}, +// vec!["fourth_completion", "fifth_completion", "sixth_completion"], +// ) +// .await; +// cx.condition(|editor, _| editor.context_menu_visible()) +// .await; - let apply_additional_edits = cx.update_editor(|editor, cx| { - editor - .confirm_completion(&ConfirmCompletion::default(), cx) - .unwrap() - }); - cx.assert_editor_state(indoc! {" - one.second_completion - two sixth_completionˇ - three sixth_completionˇ - additional edit - "}); +// let apply_additional_edits = cx.update_editor(|editor, cx| { +// editor +// .confirm_completion(&ConfirmCompletion::default(), cx) +// .unwrap() +// }); +// cx.assert_editor_state(indoc! {" +// one.second_completion +// two sixth_completionˇ +// three sixth_completionˇ +// additional edit +// "}); - handle_resolve_completion_request(&mut cx, None).await; - apply_additional_edits.await.unwrap(); +// handle_resolve_completion_request(&mut cx, None).await; +// apply_additional_edits.await.unwrap(); - cx.update(|cx| { - cx.update_global::(|settings, cx| { - settings.update_user_settings::(cx, |settings| { - settings.show_completions_on_input = Some(false); - }); - }) - }); - cx.set_state("editorˇ"); - cx.simulate_keystroke("."); - assert!(cx.editor(|e, _| e.context_menu.read().is_none())); - cx.simulate_keystroke("c"); - cx.simulate_keystroke("l"); - cx.simulate_keystroke("o"); - cx.assert_editor_state("editor.cloˇ"); - assert!(cx.editor(|e, _| e.context_menu.read().is_none())); - cx.update_editor(|editor, cx| { - editor.show_completions(&ShowCompletions, cx); - }); - handle_completion_request(&mut cx, "editor.", vec!["close", "clobber"]).await; - cx.condition(|editor, _| editor.context_menu_visible()) - .await; - let apply_additional_edits = cx.update_editor(|editor, cx| { - editor - .confirm_completion(&ConfirmCompletion::default(), cx) - .unwrap() - }); - cx.assert_editor_state("editor.closeˇ"); - handle_resolve_completion_request(&mut cx, None).await; - apply_additional_edits.await.unwrap(); -} +// cx.update(|cx| { +// cx.update_global::(|settings, cx| { +// settings.update_user_settings::(cx, |settings| { +// settings.show_completions_on_input = Some(false); +// }); +// }) +// }); +// cx.set_state("editorˇ"); +// cx.simulate_keystroke("."); +// assert!(cx.editor(|e, _| e.context_menu.read().is_none())); +// cx.simulate_keystroke("c"); +// cx.simulate_keystroke("l"); +// cx.simulate_keystroke("o"); +// cx.assert_editor_state("editor.cloˇ"); +// assert!(cx.editor(|e, _| e.context_menu.read().is_none())); +// cx.update_editor(|editor, cx| { +// editor.show_completions(&ShowCompletions, cx); +// }); +// handle_completion_request(&mut cx, "editor.", vec!["close", "clobber"]).await; +// cx.condition(|editor, _| editor.context_menu_visible()) +// .await; +// let apply_additional_edits = cx.update_editor(|editor, cx| { +// editor +// .confirm_completion(&ConfirmCompletion::default(), cx) +// .unwrap() +// }); +// cx.assert_editor_state("editor.closeˇ"); +// handle_resolve_completion_request(&mut cx, None).await; +// apply_additional_edits.await.unwrap(); +// } #[gpui::test] async fn test_toggle_comment(cx: &mut gpui::TestAppContext) { @@ -5925,7 +5929,8 @@ fn test_editing_disjoint_excerpts(cx: &mut TestAppContext) { multibuffer }); - let view = cx.add_window(|cx| build_editor(multibuffer, cx)); + let (view, mut cx) = cx.add_window_view(|cx| build_editor(multibuffer, cx)); + let cx = &mut cx; view.update(cx, |view, cx| { assert_eq!(view.text(cx), "aaaa\nbbbb"); view.change_selections(None, cx, |s| { @@ -5995,7 +6000,8 @@ fn test_editing_overlapping_excerpts(cx: &mut TestAppContext) { multibuffer }); - let view = cx.add_window(|cx| build_editor(multibuffer, cx)); + let (view, mut cx) = cx.add_window_view(|cx| build_editor(multibuffer, cx)); + let cx = &mut cx; view.update(cx, |view, cx| { let (expected_text, selection_ranges) = marked_text_ranges( indoc! {" @@ -6232,8 +6238,9 @@ async fn test_extra_newline_insertion(cx: &mut gpui::TestAppContext) { Buffer::new(0, cx.entity_id().as_u64(), text).with_language(language, cx) }); let buffer = cx.build_model(|cx| MultiBuffer::singleton(buffer, cx)); - let view = cx.add_window(|cx| build_editor(buffer, cx)); - view.condition(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) + let (view, mut cx) = cx.add_window_view(|cx| build_editor(buffer, cx)); + let cx = &mut cx; + view.condition::(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) .await; view.update(cx, |view, cx| { @@ -6307,7 +6314,7 @@ fn test_highlighted_ranges(cx: &mut TestAppContext) { let mut highlighted_ranges = editor.background_highlights_in_range( anchor_range(Point::new(3, 4)..Point::new(7, 4)), &snapshot, - theme::current(cx).as_ref(), + cx.theme().colors(), ); // Enforce a consistent ordering based on color without relying on the ordering of the // highlight's `TypeId` which is non-executor. @@ -6337,7 +6344,7 @@ fn test_highlighted_ranges(cx: &mut TestAppContext) { editor.background_highlights_in_range( anchor_range(Point::new(5, 6)..Point::new(6, 4)), &snapshot, - theme::current(cx).as_ref(), + cx.theme().colors(), ), &[( DisplayPoint::new(6, 3)..DisplayPoint::new(6, 5), @@ -6419,7 +6426,7 @@ async fn test_following(cx: &mut gpui::TestAppContext) { .unwrap() .await .unwrap(); - follower.read_with(cx, |follower, cx| { + follower.update(cx, |follower, cx| { assert_eq!(follower.selections.ranges(cx), vec![1..1]); }); assert_eq!(*is_still_following.borrow(), true); @@ -6477,7 +6484,7 @@ async fn test_following(cx: &mut gpui::TestAppContext) { .unwrap() .await .unwrap(); - follower.read_with(cx, |follower, cx| { + follower.update(cx, |follower, cx| { assert_eq!(follower.selections.ranges(cx), vec![0..0, 1..1]); }); assert_eq!(*is_still_following.borrow(), true); @@ -6493,7 +6500,7 @@ async fn test_following(cx: &mut gpui::TestAppContext) { .unwrap() .await .unwrap(); - follower.read_with(cx, |follower, cx| { + follower.update(cx, |follower, cx| { assert_eq!(follower.selections.ranges(cx), vec![0..2]); }); @@ -6511,170 +6518,171 @@ async fn test_following(cx: &mut gpui::TestAppContext) { assert_eq!(*is_still_following.borrow(), false); } -#[gpui::test] -async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) { - init_test(cx, |_| {}); +//todo!(following) +// #[gpui::test] +// async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) { +// init_test(cx, |_| {}); - let fs = FakeFs::new(cx.executor()); - let project = Project::test(fs, ["/file.rs".as_ref()], cx).await; - let workspace = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); - let pane = workspace - .read_with(cx, |workspace, _| workspace.active_pane().clone()) - .unwrap(); +// let fs = FakeFs::new(cx.executor()); +// let project = Project::test(fs, ["/file.rs".as_ref()], cx).await; +// let workspace = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); +// let pane = workspace +// .update(cx, |workspace, _| workspace.active_pane().clone()) +// .unwrap(); - let cx = &mut VisualTestContext::from_window(*workspace.deref(), cx); +// let cx = &mut VisualTestContext::from_window(*workspace.deref(), cx); - let leader = pane.update(cx, |_, cx| { - let multibuffer = cx.build_model(|_| MultiBuffer::new(0)); - cx.build_view(|cx| build_editor(multibuffer.clone(), cx)) - }); +// let leader = pane.update(cx, |_, cx| { +// let multibuffer = cx.build_model(|_| MultiBuffer::new(0)); +// cx.build_view(|cx| build_editor(multibuffer.clone(), cx)) +// }); - // Start following the editor when it has no excerpts. - let mut state_message = leader.update(cx, |leader, cx| leader.to_state_proto(cx)); - let follower_1 = cx - .update(|cx| { - Editor::from_state_proto( - pane.clone(), - workspace.root_view(cx).unwrap(), - ViewId { - creator: Default::default(), - id: 0, - }, - &mut state_message, - cx, - ) - }) - .unwrap() - .await - .unwrap(); +// // Start following the editor when it has no excerpts. +// let mut state_message = leader.update(cx, |leader, cx| leader.to_state_proto(cx)); +// let follower_1 = cx +// .update(|cx| { +// Editor::from_state_proto( +// pane.clone(), +// workspace.root_view(cx).unwrap(), +// ViewId { +// creator: Default::default(), +// id: 0, +// }, +// &mut state_message, +// cx, +// ) +// }) +// .unwrap() +// .await +// .unwrap(); - let update_message = Rc::new(RefCell::new(None)); - follower_1.update(cx, { - let update = update_message.clone(); - |_, cx| { - cx.subscribe(&leader, move |_, leader, event, cx| { - leader - .read(cx) - .add_event_to_update_proto(event, &mut *update.borrow_mut(), cx); - }) - .detach(); - } - }); +// let update_message = Rc::new(RefCell::new(None)); +// follower_1.update(cx, { +// let update = update_message.clone(); +// |_, cx| { +// cx.subscribe(&leader, move |_, leader, event, cx| { +// leader +// .read(cx) +// .add_event_to_update_proto(event, &mut *update.borrow_mut(), cx); +// }) +// .detach(); +// } +// }); - let (buffer_1, buffer_2) = project.update(cx, |project, cx| { - ( - project - .create_buffer("abc\ndef\nghi\njkl\n", None, cx) - .unwrap(), - project - .create_buffer("mno\npqr\nstu\nvwx\n", None, cx) - .unwrap(), - ) - }); +// let (buffer_1, buffer_2) = project.update(cx, |project, cx| { +// ( +// project +// .create_buffer("abc\ndef\nghi\njkl\n", None, cx) +// .unwrap(), +// project +// .create_buffer("mno\npqr\nstu\nvwx\n", None, cx) +// .unwrap(), +// ) +// }); - // Insert some excerpts. - leader.update(cx, |leader, cx| { - leader.buffer.update(cx, |multibuffer, cx| { - let excerpt_ids = multibuffer.push_excerpts( - buffer_1.clone(), - [ - ExcerptRange { - context: 1..6, - primary: None, - }, - ExcerptRange { - context: 12..15, - primary: None, - }, - ExcerptRange { - context: 0..3, - primary: None, - }, - ], - cx, - ); - multibuffer.insert_excerpts_after( - excerpt_ids[0], - buffer_2.clone(), - [ - ExcerptRange { - context: 8..12, - primary: None, - }, - ExcerptRange { - context: 0..6, - primary: None, - }, - ], - cx, - ); - }); - }); +// // Insert some excerpts. +// leader.update(cx, |leader, cx| { +// leader.buffer.update(cx, |multibuffer, cx| { +// let excerpt_ids = multibuffer.push_excerpts( +// buffer_1.clone(), +// [ +// ExcerptRange { +// context: 1..6, +// primary: None, +// }, +// ExcerptRange { +// context: 12..15, +// primary: None, +// }, +// ExcerptRange { +// context: 0..3, +// primary: None, +// }, +// ], +// cx, +// ); +// multibuffer.insert_excerpts_after( +// excerpt_ids[0], +// buffer_2.clone(), +// [ +// ExcerptRange { +// context: 8..12, +// primary: None, +// }, +// ExcerptRange { +// context: 0..6, +// primary: None, +// }, +// ], +// cx, +// ); +// }); +// }); - // Apply the update of adding the excerpts. - follower_1 - .update(cx, |follower, cx| { - follower.apply_update_proto(&project, update_message.borrow().clone().unwrap(), cx) - }) - .await - .unwrap(); - assert_eq!( - follower_1.update(cx, |editor, cx| editor.text(cx)), - leader.update(cx, |editor, cx| editor.text(cx)) - ); - update_message.borrow_mut().take(); +// // Apply the update of adding the excerpts. +// follower_1 +// .update(cx, |follower, cx| { +// follower.apply_update_proto(&project, update_message.borrow().clone().unwrap(), cx) +// }) +// .await +// .unwrap(); +// assert_eq!( +// follower_1.update(cx, |editor, cx| editor.text(cx)), +// leader.update(cx, |editor, cx| editor.text(cx)) +// ); +// update_message.borrow_mut().take(); - // Start following separately after it already has excerpts. - let mut state_message = leader.update(cx, |leader, cx| leader.to_state_proto(cx)); - let follower_2 = cx - .update(|cx| { - Editor::from_state_proto( - pane.clone(), - workspace.clone(), - ViewId { - creator: Default::default(), - id: 0, - }, - &mut state_message, - cx, - ) - }) - .unwrap() - .await - .unwrap(); - assert_eq!( - follower_2.update(cx, |editor, cx| editor.text(cx)), - leader.update(cx, |editor, cx| editor.text(cx)) - ); +// // Start following separately after it already has excerpts. +// let mut state_message = leader.update(cx, |leader, cx| leader.to_state_proto(cx)); +// let follower_2 = cx +// .update(|cx| { +// Editor::from_state_proto( +// pane.clone(), +// workspace.clone(), +// ViewId { +// creator: Default::default(), +// id: 0, +// }, +// &mut state_message, +// cx, +// ) +// }) +// .unwrap() +// .await +// .unwrap(); +// assert_eq!( +// follower_2.update(cx, |editor, cx| editor.text(cx)), +// leader.update(cx, |editor, cx| editor.text(cx)) +// ); - // Remove some excerpts. - leader.update(cx, |leader, cx| { - leader.buffer.update(cx, |multibuffer, cx| { - let excerpt_ids = multibuffer.excerpt_ids(); - multibuffer.remove_excerpts([excerpt_ids[1], excerpt_ids[2]], cx); - multibuffer.remove_excerpts([excerpt_ids[0]], cx); - }); - }); +// // Remove some excerpts. +// leader.update(cx, |leader, cx| { +// leader.buffer.update(cx, |multibuffer, cx| { +// let excerpt_ids = multibuffer.excerpt_ids(); +// multibuffer.remove_excerpts([excerpt_ids[1], excerpt_ids[2]], cx); +// multibuffer.remove_excerpts([excerpt_ids[0]], cx); +// }); +// }); - // Apply the update of removing the excerpts. - follower_1 - .update(cx, |follower, cx| { - follower.apply_update_proto(&project, update_message.borrow().clone().unwrap(), cx) - }) - .await - .unwrap(); - follower_2 - .update(cx, |follower, cx| { - follower.apply_update_proto(&project, update_message.borrow().clone().unwrap(), cx) - }) - .await - .unwrap(); - update_message.borrow_mut().take(); - assert_eq!( - follower_1.update(cx, |editor, cx| editor.text(cx)), - leader.update(cx, |editor, cx| editor.text(cx)) - ); -} +// // Apply the update of removing the excerpts. +// follower_1 +// .update(cx, |follower, cx| { +// follower.apply_update_proto(&project, update_message.borrow().clone().unwrap(), cx) +// }) +// .await +// .unwrap(); +// follower_2 +// .update(cx, |follower, cx| { +// follower.apply_update_proto(&project, update_message.borrow().clone().unwrap(), cx) +// }) +// .await +// .unwrap(); +// update_message.borrow_mut().take(); +// assert_eq!( +// follower_1.update(cx, |editor, cx| editor.text(cx)), +// leader.update(cx, |editor, cx| editor.text(cx)) +// ); +// } #[test] fn test_combine_syntax_and_fuzzy_match_highlights() { @@ -7048,255 +7056,256 @@ async fn test_move_to_enclosing_bracket(cx: &mut gpui::TestAppContext) { ); } -#[gpui::test(iterations = 10)] -async fn test_copilot(executor: BackgroundExecutor, cx: &mut gpui::TestAppContext) { - init_test(cx, |_| {}); +// todo!(completions) +// #[gpui::test(iterations = 10)] +// async fn test_copilot(executor: BackgroundExecutor, cx: &mut gpui::TestAppContext) { +// init_test(cx, |_| {}); - let (copilot, copilot_lsp) = Copilot::fake(cx); - cx.update(|cx| cx.set_global(copilot)); - let mut cx = EditorLspTestContext::new_rust( - lsp::ServerCapabilities { - completion_provider: Some(lsp::CompletionOptions { - trigger_characters: Some(vec![".".to_string(), ":".to_string()]), - ..Default::default() - }), - ..Default::default() - }, - cx, - ) - .await; +// let (copilot, copilot_lsp) = Copilot::fake(cx); +// cx.update(|cx| cx.set_global(copilot)); +// let mut cx = EditorLspTestContext::new_rust( +// lsp::ServerCapabilities { +// completion_provider: Some(lsp::CompletionOptions { +// trigger_characters: Some(vec![".".to_string(), ":".to_string()]), +// ..Default::default() +// }), +// ..Default::default() +// }, +// cx, +// ) +// .await; - // When inserting, ensure autocompletion is favored over Copilot suggestions. - cx.set_state(indoc! {" - oneˇ - two - three - "}); - cx.simulate_keystroke("."); - let _ = handle_completion_request( - &mut cx, - indoc! {" - one.|<> - two - three - "}, - vec!["completion_a", "completion_b"], - ); - handle_copilot_completion_request( - &copilot_lsp, - vec![copilot::request::Completion { - text: "one.copilot1".into(), - range: lsp::Range::new(lsp::Position::new(0, 0), lsp::Position::new(0, 4)), - ..Default::default() - }], - vec![], - ); - executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); - cx.update_editor(|editor, cx| { - assert!(editor.context_menu_visible()); - assert!(!editor.has_active_copilot_suggestion(cx)); +// // When inserting, ensure autocompletion is favored over Copilot suggestions. +// cx.set_state(indoc! {" +// oneˇ +// two +// three +// "}); +// cx.simulate_keystroke("."); +// let _ = handle_completion_request( +// &mut cx, +// indoc! {" +// one.|<> +// two +// three +// "}, +// vec!["completion_a", "completion_b"], +// ); +// handle_copilot_completion_request( +// &copilot_lsp, +// vec![copilot::request::Completion { +// text: "one.copilot1".into(), +// range: lsp::Range::new(lsp::Position::new(0, 0), lsp::Position::new(0, 4)), +// ..Default::default() +// }], +// vec![], +// ); +// executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); +// cx.update_editor(|editor, cx| { +// assert!(editor.context_menu_visible()); +// assert!(!editor.has_active_copilot_suggestion(cx)); - // Confirming a completion inserts it and hides the context menu, without showing - // the copilot suggestion afterwards. - editor - .confirm_completion(&Default::default(), cx) - .unwrap() - .detach(); - assert!(!editor.context_menu_visible()); - assert!(!editor.has_active_copilot_suggestion(cx)); - assert_eq!(editor.text(cx), "one.completion_a\ntwo\nthree\n"); - assert_eq!(editor.display_text(cx), "one.completion_a\ntwo\nthree\n"); - }); +// // Confirming a completion inserts it and hides the context menu, without showing +// // the copilot suggestion afterwards. +// editor +// .confirm_completion(&Default::default(), cx) +// .unwrap() +// .detach(); +// assert!(!editor.context_menu_visible()); +// assert!(!editor.has_active_copilot_suggestion(cx)); +// assert_eq!(editor.text(cx), "one.completion_a\ntwo\nthree\n"); +// assert_eq!(editor.display_text(cx), "one.completion_a\ntwo\nthree\n"); +// }); - // Ensure Copilot suggestions are shown right away if no autocompletion is available. - cx.set_state(indoc! {" - oneˇ - two - three - "}); - cx.simulate_keystroke("."); - let _ = handle_completion_request( - &mut cx, - indoc! {" - one.|<> - two - three - "}, - vec![], - ); - handle_copilot_completion_request( - &copilot_lsp, - vec![copilot::request::Completion { - text: "one.copilot1".into(), - range: lsp::Range::new(lsp::Position::new(0, 0), lsp::Position::new(0, 4)), - ..Default::default() - }], - vec![], - ); - executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); - cx.update_editor(|editor, cx| { - assert!(!editor.context_menu_visible()); - assert!(editor.has_active_copilot_suggestion(cx)); - assert_eq!(editor.display_text(cx), "one.copilot1\ntwo\nthree\n"); - assert_eq!(editor.text(cx), "one.\ntwo\nthree\n"); - }); +// // Ensure Copilot suggestions are shown right away if no autocompletion is available. +// cx.set_state(indoc! {" +// oneˇ +// two +// three +// "}); +// cx.simulate_keystroke("."); +// let _ = handle_completion_request( +// &mut cx, +// indoc! {" +// one.|<> +// two +// three +// "}, +// vec![], +// ); +// handle_copilot_completion_request( +// &copilot_lsp, +// vec![copilot::request::Completion { +// text: "one.copilot1".into(), +// range: lsp::Range::new(lsp::Position::new(0, 0), lsp::Position::new(0, 4)), +// ..Default::default() +// }], +// vec![], +// ); +// executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); +// cx.update_editor(|editor, cx| { +// assert!(!editor.context_menu_visible()); +// assert!(editor.has_active_copilot_suggestion(cx)); +// assert_eq!(editor.display_text(cx), "one.copilot1\ntwo\nthree\n"); +// assert_eq!(editor.text(cx), "one.\ntwo\nthree\n"); +// }); - // Reset editor, and ensure autocompletion is still favored over Copilot suggestions. - cx.set_state(indoc! {" - oneˇ - two - three - "}); - cx.simulate_keystroke("."); - let _ = handle_completion_request( - &mut cx, - indoc! {" - one.|<> - two - three - "}, - vec!["completion_a", "completion_b"], - ); - handle_copilot_completion_request( - &copilot_lsp, - vec![copilot::request::Completion { - text: "one.copilot1".into(), - range: lsp::Range::new(lsp::Position::new(0, 0), lsp::Position::new(0, 4)), - ..Default::default() - }], - vec![], - ); - executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); - cx.update_editor(|editor, cx| { - assert!(editor.context_menu_visible()); - assert!(!editor.has_active_copilot_suggestion(cx)); +// // Reset editor, and ensure autocompletion is still favored over Copilot suggestions. +// cx.set_state(indoc! {" +// oneˇ +// two +// three +// "}); +// cx.simulate_keystroke("."); +// let _ = handle_completion_request( +// &mut cx, +// indoc! {" +// one.|<> +// two +// three +// "}, +// vec!["completion_a", "completion_b"], +// ); +// handle_copilot_completion_request( +// &copilot_lsp, +// vec![copilot::request::Completion { +// text: "one.copilot1".into(), +// range: lsp::Range::new(lsp::Position::new(0, 0), lsp::Position::new(0, 4)), +// ..Default::default() +// }], +// vec![], +// ); +// executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); +// cx.update_editor(|editor, cx| { +// assert!(editor.context_menu_visible()); +// assert!(!editor.has_active_copilot_suggestion(cx)); - // When hiding the context menu, the Copilot suggestion becomes visible. - editor.hide_context_menu(cx); - assert!(!editor.context_menu_visible()); - assert!(editor.has_active_copilot_suggestion(cx)); - assert_eq!(editor.display_text(cx), "one.copilot1\ntwo\nthree\n"); - assert_eq!(editor.text(cx), "one.\ntwo\nthree\n"); - }); +// // When hiding the context menu, the Copilot suggestion becomes visible. +// editor.hide_context_menu(cx); +// assert!(!editor.context_menu_visible()); +// assert!(editor.has_active_copilot_suggestion(cx)); +// assert_eq!(editor.display_text(cx), "one.copilot1\ntwo\nthree\n"); +// assert_eq!(editor.text(cx), "one.\ntwo\nthree\n"); +// }); - // Ensure existing completion is interpolated when inserting again. - cx.simulate_keystroke("c"); - executor.run_until_parked(); - cx.update_editor(|editor, cx| { - assert!(!editor.context_menu_visible()); - assert!(editor.has_active_copilot_suggestion(cx)); - assert_eq!(editor.display_text(cx), "one.copilot1\ntwo\nthree\n"); - assert_eq!(editor.text(cx), "one.c\ntwo\nthree\n"); - }); +// // Ensure existing completion is interpolated when inserting again. +// cx.simulate_keystroke("c"); +// executor.run_until_parked(); +// cx.update_editor(|editor, cx| { +// assert!(!editor.context_menu_visible()); +// assert!(editor.has_active_copilot_suggestion(cx)); +// assert_eq!(editor.display_text(cx), "one.copilot1\ntwo\nthree\n"); +// assert_eq!(editor.text(cx), "one.c\ntwo\nthree\n"); +// }); - // After debouncing, new Copilot completions should be requested. - handle_copilot_completion_request( - &copilot_lsp, - vec![copilot::request::Completion { - text: "one.copilot2".into(), - range: lsp::Range::new(lsp::Position::new(0, 0), lsp::Position::new(0, 5)), - ..Default::default() - }], - vec![], - ); - executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); - cx.update_editor(|editor, cx| { - assert!(!editor.context_menu_visible()); - assert!(editor.has_active_copilot_suggestion(cx)); - assert_eq!(editor.display_text(cx), "one.copilot2\ntwo\nthree\n"); - assert_eq!(editor.text(cx), "one.c\ntwo\nthree\n"); +// // After debouncing, new Copilot completions should be requested. +// handle_copilot_completion_request( +// &copilot_lsp, +// vec![copilot::request::Completion { +// text: "one.copilot2".into(), +// range: lsp::Range::new(lsp::Position::new(0, 0), lsp::Position::new(0, 5)), +// ..Default::default() +// }], +// vec![], +// ); +// executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); +// cx.update_editor(|editor, cx| { +// assert!(!editor.context_menu_visible()); +// assert!(editor.has_active_copilot_suggestion(cx)); +// assert_eq!(editor.display_text(cx), "one.copilot2\ntwo\nthree\n"); +// assert_eq!(editor.text(cx), "one.c\ntwo\nthree\n"); - // Canceling should remove the active Copilot suggestion. - editor.cancel(&Default::default(), cx); - assert!(!editor.has_active_copilot_suggestion(cx)); - assert_eq!(editor.display_text(cx), "one.c\ntwo\nthree\n"); - assert_eq!(editor.text(cx), "one.c\ntwo\nthree\n"); +// // Canceling should remove the active Copilot suggestion. +// editor.cancel(&Default::default(), cx); +// assert!(!editor.has_active_copilot_suggestion(cx)); +// assert_eq!(editor.display_text(cx), "one.c\ntwo\nthree\n"); +// assert_eq!(editor.text(cx), "one.c\ntwo\nthree\n"); - // After canceling, tabbing shouldn't insert the previously shown suggestion. - editor.tab(&Default::default(), cx); - assert!(!editor.has_active_copilot_suggestion(cx)); - assert_eq!(editor.display_text(cx), "one.c \ntwo\nthree\n"); - assert_eq!(editor.text(cx), "one.c \ntwo\nthree\n"); +// // After canceling, tabbing shouldn't insert the previously shown suggestion. +// editor.tab(&Default::default(), cx); +// assert!(!editor.has_active_copilot_suggestion(cx)); +// assert_eq!(editor.display_text(cx), "one.c \ntwo\nthree\n"); +// assert_eq!(editor.text(cx), "one.c \ntwo\nthree\n"); - // When undoing the previously active suggestion is shown again. - editor.undo(&Default::default(), cx); - assert!(editor.has_active_copilot_suggestion(cx)); - assert_eq!(editor.display_text(cx), "one.copilot2\ntwo\nthree\n"); - assert_eq!(editor.text(cx), "one.c\ntwo\nthree\n"); - }); +// // When undoing the previously active suggestion is shown again. +// editor.undo(&Default::default(), cx); +// assert!(editor.has_active_copilot_suggestion(cx)); +// assert_eq!(editor.display_text(cx), "one.copilot2\ntwo\nthree\n"); +// assert_eq!(editor.text(cx), "one.c\ntwo\nthree\n"); +// }); - // If an edit occurs outside of this editor, the suggestion is still correctly interpolated. - cx.update_buffer(|buffer, cx| buffer.edit([(5..5, "o")], None, cx)); - cx.update_editor(|editor, cx| { - assert!(editor.has_active_copilot_suggestion(cx)); - assert_eq!(editor.display_text(cx), "one.copilot2\ntwo\nthree\n"); - assert_eq!(editor.text(cx), "one.co\ntwo\nthree\n"); +// // If an edit occurs outside of this editor, the suggestion is still correctly interpolated. +// cx.update_buffer(|buffer, cx| buffer.edit([(5..5, "o")], None, cx)); +// cx.update_editor(|editor, cx| { +// assert!(editor.has_active_copilot_suggestion(cx)); +// assert_eq!(editor.display_text(cx), "one.copilot2\ntwo\nthree\n"); +// assert_eq!(editor.text(cx), "one.co\ntwo\nthree\n"); - // Tabbing when there is an active suggestion inserts it. - editor.tab(&Default::default(), cx); - assert!(!editor.has_active_copilot_suggestion(cx)); - assert_eq!(editor.display_text(cx), "one.copilot2\ntwo\nthree\n"); - assert_eq!(editor.text(cx), "one.copilot2\ntwo\nthree\n"); +// // Tabbing when there is an active suggestion inserts it. +// editor.tab(&Default::default(), cx); +// assert!(!editor.has_active_copilot_suggestion(cx)); +// assert_eq!(editor.display_text(cx), "one.copilot2\ntwo\nthree\n"); +// assert_eq!(editor.text(cx), "one.copilot2\ntwo\nthree\n"); - // When undoing the previously active suggestion is shown again. - editor.undo(&Default::default(), cx); - assert!(editor.has_active_copilot_suggestion(cx)); - assert_eq!(editor.display_text(cx), "one.copilot2\ntwo\nthree\n"); - assert_eq!(editor.text(cx), "one.co\ntwo\nthree\n"); +// // When undoing the previously active suggestion is shown again. +// editor.undo(&Default::default(), cx); +// assert!(editor.has_active_copilot_suggestion(cx)); +// assert_eq!(editor.display_text(cx), "one.copilot2\ntwo\nthree\n"); +// assert_eq!(editor.text(cx), "one.co\ntwo\nthree\n"); - // Hide suggestion. - editor.cancel(&Default::default(), cx); - assert!(!editor.has_active_copilot_suggestion(cx)); - assert_eq!(editor.display_text(cx), "one.co\ntwo\nthree\n"); - assert_eq!(editor.text(cx), "one.co\ntwo\nthree\n"); - }); +// // Hide suggestion. +// editor.cancel(&Default::default(), cx); +// assert!(!editor.has_active_copilot_suggestion(cx)); +// assert_eq!(editor.display_text(cx), "one.co\ntwo\nthree\n"); +// assert_eq!(editor.text(cx), "one.co\ntwo\nthree\n"); +// }); - // If an edit occurs outside of this editor but no suggestion is being shown, - // we won't make it visible. - cx.update_buffer(|buffer, cx| buffer.edit([(6..6, "p")], None, cx)); - cx.update_editor(|editor, cx| { - assert!(!editor.has_active_copilot_suggestion(cx)); - assert_eq!(editor.display_text(cx), "one.cop\ntwo\nthree\n"); - assert_eq!(editor.text(cx), "one.cop\ntwo\nthree\n"); - }); +// // If an edit occurs outside of this editor but no suggestion is being shown, +// // we won't make it visible. +// cx.update_buffer(|buffer, cx| buffer.edit([(6..6, "p")], None, cx)); +// cx.update_editor(|editor, cx| { +// assert!(!editor.has_active_copilot_suggestion(cx)); +// assert_eq!(editor.display_text(cx), "one.cop\ntwo\nthree\n"); +// assert_eq!(editor.text(cx), "one.cop\ntwo\nthree\n"); +// }); - // Reset the editor to verify how suggestions behave when tabbing on leading indentation. - cx.update_editor(|editor, cx| { - editor.set_text("fn foo() {\n \n}", cx); - editor.change_selections(None, cx, |s| { - s.select_ranges([Point::new(1, 2)..Point::new(1, 2)]) - }); - }); - handle_copilot_completion_request( - &copilot_lsp, - vec![copilot::request::Completion { - text: " let x = 4;".into(), - range: lsp::Range::new(lsp::Position::new(1, 0), lsp::Position::new(1, 2)), - ..Default::default() - }], - vec![], - ); +// // Reset the editor to verify how suggestions behave when tabbing on leading indentation. +// cx.update_editor(|editor, cx| { +// editor.set_text("fn foo() {\n \n}", cx); +// editor.change_selections(None, cx, |s| { +// s.select_ranges([Point::new(1, 2)..Point::new(1, 2)]) +// }); +// }); +// handle_copilot_completion_request( +// &copilot_lsp, +// vec![copilot::request::Completion { +// text: " let x = 4;".into(), +// range: lsp::Range::new(lsp::Position::new(1, 0), lsp::Position::new(1, 2)), +// ..Default::default() +// }], +// vec![], +// ); - cx.update_editor(|editor, cx| editor.next_copilot_suggestion(&Default::default(), cx)); - executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); - cx.update_editor(|editor, cx| { - assert!(editor.has_active_copilot_suggestion(cx)); - assert_eq!(editor.display_text(cx), "fn foo() {\n let x = 4;\n}"); - assert_eq!(editor.text(cx), "fn foo() {\n \n}"); +// cx.update_editor(|editor, cx| editor.next_copilot_suggestion(&Default::default(), cx)); +// executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT); +// cx.update_editor(|editor, cx| { +// assert!(editor.has_active_copilot_suggestion(cx)); +// assert_eq!(editor.display_text(cx), "fn foo() {\n let x = 4;\n}"); +// assert_eq!(editor.text(cx), "fn foo() {\n \n}"); - // Tabbing inside of leading whitespace inserts indentation without accepting the suggestion. - editor.tab(&Default::default(), cx); - assert!(editor.has_active_copilot_suggestion(cx)); - assert_eq!(editor.text(cx), "fn foo() {\n \n}"); - assert_eq!(editor.display_text(cx), "fn foo() {\n let x = 4;\n}"); +// // Tabbing inside of leading whitespace inserts indentation without accepting the suggestion. +// editor.tab(&Default::default(), cx); +// assert!(editor.has_active_copilot_suggestion(cx)); +// assert_eq!(editor.text(cx), "fn foo() {\n \n}"); +// assert_eq!(editor.display_text(cx), "fn foo() {\n let x = 4;\n}"); - // Tabbing again accepts the suggestion. - editor.tab(&Default::default(), cx); - assert!(!editor.has_active_copilot_suggestion(cx)); - assert_eq!(editor.text(cx), "fn foo() {\n let x = 4;\n}"); - assert_eq!(editor.display_text(cx), "fn foo() {\n let x = 4;\n}"); - }); -} +// // Tabbing again accepts the suggestion. +// editor.tab(&Default::default(), cx); +// assert!(!editor.has_active_copilot_suggestion(cx)); +// assert_eq!(editor.text(cx), "fn foo() {\n let x = 4;\n}"); +// assert_eq!(editor.display_text(cx), "fn foo() {\n let x = 4;\n}"); +// }); +// } #[gpui::test] async fn test_copilot_completion_invalidation( @@ -7606,7 +7615,7 @@ async fn test_on_type_formatting_not_triggered(cx: &mut gpui::TestAppContext) { let worktree_id = workspace .update(cx, |workspace, cx| { - workspace.project().read_with(cx, |project, cx| { + workspace.project().update(cx, |project, cx| { project.worktrees().next().unwrap().read(cx).id() }) }) @@ -7648,7 +7657,7 @@ async fn test_on_type_formatting_not_triggered(cx: &mut gpui::TestAppContext) { }); editor_handle.update(cx, |editor, cx| { - cx.focus(&editor_handle); + editor.focus(cx); editor.change_selections(None, cx, |s| { s.select_ranges([Point::new(0, 21)..Point::new(0, 20)]) }); @@ -7657,7 +7666,7 @@ async fn test_on_type_formatting_not_triggered(cx: &mut gpui::TestAppContext) { cx.executor().run_until_parked(); - buffer.read_with(cx, |buffer, _| { + buffer.update(cx, |buffer, _| { assert_eq!( buffer.text(), "fn main() { let a = {5}; }", @@ -7802,196 +7811,197 @@ async fn test_language_server_restart_due_to_settings_change(cx: &mut gpui::Test ); } -#[gpui::test] -async fn test_completions_with_additional_edits(cx: &mut gpui::TestAppContext) { - init_test(cx, |_| {}); +//todo!(completions) +// #[gpui::test] +// async fn test_completions_with_additional_edits(cx: &mut gpui::TestAppContext) { +// init_test(cx, |_| {}); - let mut cx = EditorLspTestContext::new_rust( - lsp::ServerCapabilities { - completion_provider: Some(lsp::CompletionOptions { - trigger_characters: Some(vec![".".to_string()]), - resolve_provider: Some(true), - ..Default::default() - }), - ..Default::default() - }, - cx, - ) - .await; +// let mut cx = EditorLspTestContext::new_rust( +// lsp::ServerCapabilities { +// completion_provider: Some(lsp::CompletionOptions { +// trigger_characters: Some(vec![".".to_string()]), +// resolve_provider: Some(true), +// ..Default::default() +// }), +// ..Default::default() +// }, +// cx, +// ) +// .await; - cx.set_state(indoc! {"fn main() { let a = 2ˇ; }"}); - cx.simulate_keystroke("."); - let completion_item = lsp::CompletionItem { - label: "some".into(), - kind: Some(lsp::CompletionItemKind::SNIPPET), - detail: Some("Wrap the expression in an `Option::Some`".to_string()), - documentation: Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { - kind: lsp::MarkupKind::Markdown, - value: "```rust\nSome(2)\n```".to_string(), - })), - deprecated: Some(false), - sort_text: Some("fffffff2".to_string()), - filter_text: Some("some".to_string()), - insert_text_format: Some(lsp::InsertTextFormat::SNIPPET), - text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { - range: lsp::Range { - start: lsp::Position { - line: 0, - character: 22, - }, - end: lsp::Position { - line: 0, - character: 22, - }, - }, - new_text: "Some(2)".to_string(), - })), - additional_text_edits: Some(vec![lsp::TextEdit { - range: lsp::Range { - start: lsp::Position { - line: 0, - character: 20, - }, - end: lsp::Position { - line: 0, - character: 22, - }, - }, - new_text: "".to_string(), - }]), - ..Default::default() - }; +// cx.set_state(indoc! {"fn main() { let a = 2ˇ; }"}); +// cx.simulate_keystroke("."); +// let completion_item = lsp::CompletionItem { +// label: "some".into(), +// kind: Some(lsp::CompletionItemKind::SNIPPET), +// detail: Some("Wrap the expression in an `Option::Some`".to_string()), +// documentation: Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { +// kind: lsp::MarkupKind::Markdown, +// value: "```rust\nSome(2)\n```".to_string(), +// })), +// deprecated: Some(false), +// sort_text: Some("fffffff2".to_string()), +// filter_text: Some("some".to_string()), +// insert_text_format: Some(lsp::InsertTextFormat::SNIPPET), +// text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { +// range: lsp::Range { +// start: lsp::Position { +// line: 0, +// character: 22, +// }, +// end: lsp::Position { +// line: 0, +// character: 22, +// }, +// }, +// new_text: "Some(2)".to_string(), +// })), +// additional_text_edits: Some(vec![lsp::TextEdit { +// range: lsp::Range { +// start: lsp::Position { +// line: 0, +// character: 20, +// }, +// end: lsp::Position { +// line: 0, +// character: 22, +// }, +// }, +// new_text: "".to_string(), +// }]), +// ..Default::default() +// }; - let closure_completion_item = completion_item.clone(); - let mut request = cx.handle_request::(move |_, _, _| { - let task_completion_item = closure_completion_item.clone(); - async move { - Ok(Some(lsp::CompletionResponse::Array(vec![ - task_completion_item, - ]))) - } - }); +// let closure_completion_item = completion_item.clone(); +// let mut request = cx.handle_request::(move |_, _, _| { +// let task_completion_item = closure_completion_item.clone(); +// async move { +// Ok(Some(lsp::CompletionResponse::Array(vec![ +// task_completion_item, +// ]))) +// } +// }); - request.next().await; +// request.next().await; - cx.condition(|editor, _| editor.context_menu_visible()) - .await; - let apply_additional_edits = cx.update_editor(|editor, cx| { - editor - .confirm_completion(&ConfirmCompletion::default(), cx) - .unwrap() - }); - cx.assert_editor_state(indoc! {"fn main() { let a = 2.Some(2)ˇ; }"}); +// cx.condition(|editor, _| editor.context_menu_visible()) +// .await; +// let apply_additional_edits = cx.update_editor(|editor, cx| { +// editor +// .confirm_completion(&ConfirmCompletion::default(), cx) +// .unwrap() +// }); +// cx.assert_editor_state(indoc! {"fn main() { let a = 2.Some(2)ˇ; }"}); - cx.handle_request::(move |_, _, _| { - let task_completion_item = completion_item.clone(); - async move { Ok(task_completion_item) } - }) - .next() - .await - .unwrap(); - apply_additional_edits.await.unwrap(); - cx.assert_editor_state(indoc! {"fn main() { let a = Some(2)ˇ; }"}); -} +// cx.handle_request::(move |_, _, _| { +// let task_completion_item = completion_item.clone(); +// async move { Ok(task_completion_item) } +// }) +// .next() +// .await +// .unwrap(); +// apply_additional_edits.await.unwrap(); +// cx.assert_editor_state(indoc! {"fn main() { let a = Some(2)ˇ; }"}); +// } -#[gpui::test] -async fn test_completions_in_languages_with_extra_word_characters(cx: &mut gpui::TestAppContext) { - init_test(cx, |_| {}); +// #[gpui::test] +// async fn test_completions_in_languages_with_extra_word_characters(cx: &mut gpui::TestAppContext) { +// init_test(cx, |_| {}); - let mut cx = EditorLspTestContext::new( - Language::new( - LanguageConfig { - path_suffixes: vec!["jsx".into()], - overrides: [( - "element".into(), - LanguageConfigOverride { - word_characters: Override::Set(['-'].into_iter().collect()), - ..Default::default() - }, - )] - .into_iter() - .collect(), - ..Default::default() - }, - Some(tree_sitter_typescript::language_tsx()), - ) - .with_override_query("(jsx_self_closing_element) @element") - .unwrap(), - lsp::ServerCapabilities { - completion_provider: Some(lsp::CompletionOptions { - trigger_characters: Some(vec![":".to_string()]), - ..Default::default() - }), - ..Default::default() - }, - cx, - ) - .await; +// let mut cx = EditorLspTestContext::new( +// Language::new( +// LanguageConfig { +// path_suffixes: vec!["jsx".into()], +// overrides: [( +// "element".into(), +// LanguageConfigOverride { +// word_characters: Override::Set(['-'].into_iter().collect()), +// ..Default::default() +// }, +// )] +// .into_iter() +// .collect(), +// ..Default::default() +// }, +// Some(tree_sitter_typescript::language_tsx()), +// ) +// .with_override_query("(jsx_self_closing_element) @element") +// .unwrap(), +// lsp::ServerCapabilities { +// completion_provider: Some(lsp::CompletionOptions { +// trigger_characters: Some(vec![":".to_string()]), +// ..Default::default() +// }), +// ..Default::default() +// }, +// cx, +// ) +// .await; - cx.lsp - .handle_request::(move |_, _| async move { - Ok(Some(lsp::CompletionResponse::Array(vec![ - lsp::CompletionItem { - label: "bg-blue".into(), - ..Default::default() - }, - lsp::CompletionItem { - label: "bg-red".into(), - ..Default::default() - }, - lsp::CompletionItem { - label: "bg-yellow".into(), - ..Default::default() - }, - ]))) - }); +// cx.lsp +// .handle_request::(move |_, _| async move { +// Ok(Some(lsp::CompletionResponse::Array(vec![ +// lsp::CompletionItem { +// label: "bg-blue".into(), +// ..Default::default() +// }, +// lsp::CompletionItem { +// label: "bg-red".into(), +// ..Default::default() +// }, +// lsp::CompletionItem { +// label: "bg-yellow".into(), +// ..Default::default() +// }, +// ]))) +// }); - cx.set_state(r#"

"#); +// cx.set_state(r#"

"#); - // Trigger completion when typing a dash, because the dash is an extra - // word character in the 'element' scope, which contains the cursor. - cx.simulate_keystroke("-"); - cx.executor().run_until_parked(); - cx.update_editor(|editor, _| { - if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() { - assert_eq!( - menu.matches.iter().map(|m| &m.string).collect::>(), - &["bg-red", "bg-blue", "bg-yellow"] - ); - } else { - panic!("expected completion menu to be open"); - } - }); +// // Trigger completion when typing a dash, because the dash is an extra +// // word character in the 'element' scope, which contains the cursor. +// cx.simulate_keystroke("-"); +// cx.executor().run_until_parked(); +// cx.update_editor(|editor, _| { +// if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() { +// assert_eq!( +// menu.matches.iter().map(|m| &m.string).collect::>(), +// &["bg-red", "bg-blue", "bg-yellow"] +// ); +// } else { +// panic!("expected completion menu to be open"); +// } +// }); - cx.simulate_keystroke("l"); - cx.executor().run_until_parked(); - cx.update_editor(|editor, _| { - if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() { - assert_eq!( - menu.matches.iter().map(|m| &m.string).collect::>(), - &["bg-blue", "bg-yellow"] - ); - } else { - panic!("expected completion menu to be open"); - } - }); +// cx.simulate_keystroke("l"); +// cx.executor().run_until_parked(); +// cx.update_editor(|editor, _| { +// if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() { +// assert_eq!( +// menu.matches.iter().map(|m| &m.string).collect::>(), +// &["bg-blue", "bg-yellow"] +// ); +// } else { +// panic!("expected completion menu to be open"); +// } +// }); - // When filtering completions, consider the character after the '-' to - // be the start of a subword. - cx.set_state(r#"

"#); - cx.simulate_keystroke("l"); - cx.executor().run_until_parked(); - cx.update_editor(|editor, _| { - if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() { - assert_eq!( - menu.matches.iter().map(|m| &m.string).collect::>(), - &["bg-yellow"] - ); - } else { - panic!("expected completion menu to be open"); - } - }); -} +// // When filtering completions, consider the character after the '-' to +// // be the start of a subword. +// cx.set_state(r#"

"#); +// cx.simulate_keystroke("l"); +// cx.executor().run_until_parked(); +// cx.update_editor(|editor, _| { +// if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() { +// assert_eq!( +// menu.matches.iter().map(|m| &m.string).collect::>(), +// &["bg-yellow"] +// ); +// } else { +// panic!("expected completion menu to be open"); +// } +// }); +// } #[gpui::test] async fn test_document_format_with_prettier(cx: &mut gpui::TestAppContext) { @@ -8032,17 +8042,18 @@ async fn test_document_format_with_prettier(cx: &mut gpui::TestAppContext) { let buffer_text = "one\ntwo\nthree\n"; let buffer = cx.build_model(|cx| MultiBuffer::singleton(buffer, cx)); - let editor = cx.add_window(|cx| build_editor(buffer, cx)); + let (editor, mut cx) = cx.add_window_view(|cx| build_editor(buffer, cx)); + let cx = &mut cx; editor.update(cx, |editor, cx| editor.set_text(buffer_text, cx)); - let format = editor + editor .update(cx, |editor, cx| { editor.perform_format(project.clone(), FormatTrigger::Manual, cx) }) - .unwrap(); - format.await.unwrap(); + .unwrap() + .await; assert_eq!( - editor.read_with(cx, |editor, cx| editor.text(cx)), + editor.update(cx, |editor, cx| editor.text(cx)), buffer_text.to_string() + prettier_format_suffix, "Test prettier formatting was not applied to the original buffer text", ); @@ -8055,7 +8066,7 @@ async fn test_document_format_with_prettier(cx: &mut gpui::TestAppContext) { }); format.await.unwrap(); assert_eq!( - editor.read_with(cx, |editor, cx| editor.text(cx)), + editor.update(cx, |editor, cx| editor.text(cx)), buffer_text.to_string() + prettier_format_suffix + "\n" + prettier_format_suffix, "Autoformatting (via test prettier) was not applied to the original buffer text", ); @@ -8185,7 +8196,7 @@ pub(crate) fn update_test_language_settings( f: impl Fn(&mut AllLanguageSettingsContent), ) { cx.update(|cx| { - cx.update_global::(|store, cx| { + cx.update_global(|store: &mut SettingsStore, cx| { store.update_user_settings::(cx, f); }); }); @@ -8196,7 +8207,7 @@ pub(crate) fn update_test_project_settings( f: impl Fn(&mut ProjectSettings), ) { cx.update(|cx| { - cx.update_global::(|store, cx| { + cx.update_global(|store: &mut SettingsStore, cx| { store.update_user_settings::(cx, f); }); }); @@ -8204,7 +8215,8 @@ pub(crate) fn update_test_project_settings( pub(crate) fn init_test(cx: &mut TestAppContext, f: fn(&mut AllLanguageSettingsContent)) { cx.update(|cx| { - cx.set_global(SettingsStore::test(cx)); + let store = SettingsStore::test(cx); + cx.set_global(store); theme::init(cx); client::init_settings(cx); language::init(cx); diff --git a/crates/editor2/src/test/editor_lsp_test_context.rs b/crates/editor2/src/test/editor_lsp_test_context.rs index d48e911a9f..afcefad6b2 100644 --- a/crates/editor2/src/test/editor_lsp_test_context.rs +++ b/crates/editor2/src/test/editor_lsp_test_context.rs @@ -10,7 +10,7 @@ use serde_json::json; use crate::{Editor, ToPoint}; use collections::HashSet; use futures::Future; -use gpui::{json, View, ViewContext}; +use gpui::{View, ViewContext, VisualTestContext}; use indoc::indoc; use language::{point_to_lsp, FakeLspAdapter, Language, LanguageConfig, LanguageQueries}; use lsp::{notification, request}; @@ -19,7 +19,7 @@ use project::Project; use smol::stream::StreamExt; use workspace::{AppState, Workspace, WorkspaceHandle}; -use super::editor_test_context::EditorTestContext; +use super::editor_test_context::{AssertionContextManager, EditorTestContext}; pub struct EditorLspTestContext<'a> { pub cx: EditorTestContext<'a>, @@ -34,8 +34,6 @@ impl<'a> EditorLspTestContext<'a> { capabilities: lsp::ServerCapabilities, cx: &'a mut gpui::TestAppContext, ) -> EditorLspTestContext<'a> { - use json::json; - let app_state = cx.update(AppState::test); cx.update(|cx| { @@ -70,9 +68,10 @@ impl<'a> EditorLspTestContext<'a> { .await; let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); - let workspace = window.root(cx); + let workspace = window.root_view(cx).unwrap(); + let mut cx = VisualTestContext::from_window(*window.deref(), cx); project - .update(cx, |project, cx| { + .update(&mut cx, |project, cx| { project.find_or_create_local_worktree("/root", true, cx) }) .await @@ -82,7 +81,7 @@ impl<'a> EditorLspTestContext<'a> { let file = cx.read(|cx| workspace.file_project_paths(cx)[0].clone()); let item = workspace - .update(cx, |workspace, cx| { + .update(&mut cx, |workspace, cx| { workspace.open_path(file, None, true, cx) }) .await @@ -92,7 +91,7 @@ impl<'a> EditorLspTestContext<'a> { item.act_as::(cx) .expect("Opened test file wasn't an editor") }); - editor.update(cx, |_, cx| cx.focus_self()); + editor.update(&mut cx, |editor, cx| editor.focus(cx)); let lsp = fake_servers.next().await.unwrap(); @@ -101,6 +100,7 @@ impl<'a> EditorLspTestContext<'a> { cx, window: window.into(), editor, + assertion_cx: AssertionContextManager::new(), }, lsp, workspace, @@ -258,7 +258,7 @@ impl<'a> EditorLspTestContext<'a> { where F: FnOnce(&mut Workspace, &mut ViewContext) -> T, { - self.workspace.update(self.cx.cx, update) + self.workspace.update(&mut self.cx.cx, update) } pub fn handle_request( diff --git a/crates/editor2/src/test/editor_test_context.rs b/crates/editor2/src/test/editor_test_context.rs index 304e4fcd2b..c865538b0c 100644 --- a/crates/editor2/src/test/editor_test_context.rs +++ b/crates/editor2/src/test/editor_test_context.rs @@ -1,28 +1,37 @@ use crate::{ display_map::ToDisplayPoint, AnchorRangeExt, Autoscroll, DisplayPoint, Editor, MultiBuffer, }; +use collections::BTreeMap; use futures::Future; use gpui::{ AnyWindowHandle, AppContext, ForegroundExecutor, Keystroke, ModelContext, View, ViewContext, + VisualTestContext, WindowHandle, }; use indoc::indoc; +use itertools::Itertools; use language::{Buffer, BufferSnapshot}; +use parking_lot::RwLock; use project::{FakeFs, Project}; use std::{ any::TypeId, ops::{Deref, DerefMut, Range}, + sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, + }, }; use util::{ assert_set_eq, test::{generate_marked_text, marked_text_ranges}, }; -// use super::build_editor_with_project; +use super::build_editor_with_project; pub struct EditorTestContext<'a> { - pub cx: &'a mut gpui::TestAppContext, + pub cx: gpui::VisualTestContext<'a>, pub window: AnyWindowHandle, pub editor: View, + pub assertion_cx: AssertionContextManager, } impl<'a> EditorTestContext<'a> { @@ -43,15 +52,18 @@ impl<'a> EditorTestContext<'a> { }) .await .unwrap(); - let window = cx.add_window(|cx| { - cx.focus_self(); - build_editor_with_project(project, MultiBuffer::build_from_buffer(buffer, cx), cx) + let editor = cx.add_window(|cx| { + let editor = + build_editor_with_project(project, MultiBuffer::build_from_buffer(buffer, cx), cx); + editor.focus(cx); + editor }); - let editor = window.root(cx); + let editor_view = editor.root_view(cx).unwrap(); Self { - cx, - window: window.into(), - editor, + cx: VisualTestContext::from_window(*editor.deref(), cx), + window: editor.into(), + editor: editor_view, + assertion_cx: AssertionContextManager::new(), } } @@ -59,24 +71,27 @@ impl<'a> EditorTestContext<'a> { &self, predicate: impl FnMut(&Editor, &AppContext) -> bool, ) -> impl Future { - self.editor.condition(self.cx, predicate) + self.editor.condition::(&self.cx, predicate) } - pub fn editor(&self, read: F) -> T + #[track_caller] + pub fn editor(&mut self, read: F) -> T where F: FnOnce(&Editor, &ViewContext) -> T, { - self.editor.update(self.cx, read) + self.editor + .update(&mut self.cx, |this, cx| read(&this, &cx)) } + #[track_caller] pub fn update_editor(&mut self, update: F) -> T where F: FnOnce(&mut Editor, &mut ViewContext) -> T, { - self.editor.update(self.cx, update) + self.editor.update(&mut self.cx, update) } - pub fn multibuffer(&self, read: F) -> T + pub fn multibuffer(&mut self, read: F) -> T where F: FnOnce(&MultiBuffer, &AppContext) -> T, { @@ -90,11 +105,11 @@ impl<'a> EditorTestContext<'a> { self.update_editor(|editor, cx| editor.buffer().update(cx, update)) } - pub fn buffer_text(&self) -> String { + pub fn buffer_text(&mut self) -> String { self.multibuffer(|buffer, cx| buffer.snapshot(cx).text()) } - pub fn buffer(&self, read: F) -> T + pub fn buffer(&mut self, read: F) -> T where F: FnOnce(&Buffer, &AppContext) -> T, { @@ -114,10 +129,18 @@ impl<'a> EditorTestContext<'a> { }) } - pub fn buffer_snapshot(&self) -> BufferSnapshot { + pub fn buffer_snapshot(&mut self) -> BufferSnapshot { self.buffer(|buffer, _| buffer.snapshot()) } + pub fn add_assertion_context(&self, context: String) -> ContextHandle { + self.assertion_cx.add_context(context) + } + + pub fn assertion_context(&self) -> String { + self.assertion_cx.context() + } + pub fn simulate_keystroke(&mut self, keystroke_text: &str) -> ContextHandle { let keystroke_under_test_handle = self.add_assertion_context(format!("Simulated Keystroke: {:?}", keystroke_text)); @@ -141,16 +164,12 @@ impl<'a> EditorTestContext<'a> { // before returning. // NOTE: we don't do this in simulate_keystroke() because a possible cause of bugs is that typing too // quickly races with async actions. - if let Foreground::Deterministic { cx_id: _, executor } = self.cx.foreground().as_ref() { - executor.run_until_parked(); - } else { - unreachable!(); - } + self.cx.background_executor.run_until_parked(); keystrokes_under_test_handle } - pub fn ranges(&self, marked_text: &str) -> Vec> { + pub fn ranges(&mut self, marked_text: &str) -> Vec> { let (unmarked_text, ranges) = marked_text_ranges(marked_text, false); assert_eq!(self.buffer_text(), unmarked_text); ranges @@ -160,12 +179,12 @@ impl<'a> EditorTestContext<'a> { let ranges = self.ranges(marked_text); let snapshot = self .editor - .update(self.cx, |editor, cx| editor.snapshot(cx)); + .update(&mut self.cx, |editor, cx| editor.snapshot(cx)); ranges[0].start.to_display_point(&snapshot) } // Returns anchors for the current buffer using `«` and `»` - pub fn text_anchor_range(&self, marked_text: &str) -> Range { + pub fn text_anchor_range(&mut self, marked_text: &str) -> Range { let ranges = self.ranges(marked_text); let snapshot = self.buffer_snapshot(); snapshot.anchor_before(ranges[0].start)..snapshot.anchor_after(ranges[0].end) @@ -190,7 +209,7 @@ impl<'a> EditorTestContext<'a> { marked_text.escape_debug().to_string() )); let (unmarked_text, selection_ranges) = marked_text_ranges(marked_text, true); - self.editor.update(self.cx, |editor, cx| { + self.editor.update(&mut self.cx, |editor, cx| { editor.set_text(unmarked_text, cx); editor.change_selections(Some(Autoscroll::fit()), cx, |s| { s.select_ranges(selection_ranges) @@ -206,7 +225,7 @@ impl<'a> EditorTestContext<'a> { marked_text.escape_debug().to_string() )); let (unmarked_text, selection_ranges) = marked_text_ranges(marked_text, true); - self.editor.update(self.cx, |editor, cx| { + self.editor.update(&mut self.cx, |editor, cx| { assert_eq!(editor.text(cx), unmarked_text); editor.change_selections(Some(Autoscroll::fit()), cx, |s| { s.select_ranges(selection_ranges) @@ -273,9 +292,12 @@ impl<'a> EditorTestContext<'a> { self.assert_selections(expected_selections, expected_marked_text) } - fn editor_selections(&self) -> Vec> { + #[track_caller] + fn editor_selections(&mut self) -> Vec> { self.editor - .read_with(self.cx, |editor, cx| editor.selections.all::(cx)) + .update(&mut self.cx, |editor, cx| { + editor.selections.all::(cx) + }) .into_iter() .map(|s| { if s.reversed { @@ -320,7 +342,7 @@ impl<'a> Deref for EditorTestContext<'a> { type Target = gpui::TestAppContext; fn deref(&self) -> &Self::Target { - self.cx + &self.cx } } @@ -329,3 +351,50 @@ impl<'a> DerefMut for EditorTestContext<'a> { &mut self.cx } } + +/// Tracks string context to be printed when assertions fail. +/// Often this is done by storing a context string in the manager and returning the handle. +#[derive(Clone)] +pub struct AssertionContextManager { + id: Arc, + contexts: Arc>>, +} + +impl AssertionContextManager { + pub fn new() -> Self { + Self { + id: Arc::new(AtomicUsize::new(0)), + contexts: Arc::new(RwLock::new(BTreeMap::new())), + } + } + + pub fn add_context(&self, context: String) -> ContextHandle { + let id = self.id.fetch_add(1, Ordering::Relaxed); + let mut contexts = self.contexts.write(); + contexts.insert(id, context); + ContextHandle { + id, + manager: self.clone(), + } + } + + pub fn context(&self) -> String { + let contexts = self.contexts.read(); + format!("\n{}\n", contexts.values().join("\n")) + } +} + +/// Used to track the lifetime of a piece of context so that it can be provided when an assertion fails. +/// For example, in the EditorTestContext, `set_state` returns a context handle so that if an assertion fails, +/// the state that was set initially for the failure can be printed in the error message +pub struct ContextHandle { + id: usize, + manager: AssertionContextManager, +} + +impl Drop for ContextHandle { + fn drop(&mut self) { + let mut contexts = self.manager.contexts.write(); + contexts.remove(&self.id); + } +} diff --git a/crates/gpui2/src/app/test_context.rs b/crates/gpui2/src/app/test_context.rs index 82c7f11e1c..2e99477674 100644 --- a/crates/gpui2/src/app/test_context.rs +++ b/crates/gpui2/src/app/test_context.rs @@ -6,7 +6,7 @@ use crate::{ }; use anyhow::{anyhow, bail}; use futures::{Stream, StreamExt}; -use std::{future::Future, rc::Rc, sync::Arc, time::Duration}; +use std::{future::Future, ops::Deref, rc::Rc, sync::Arc, time::Duration}; #[derive(Clone)] pub struct TestAppContext { @@ -132,6 +132,18 @@ impl TestAppContext { cx.open_window(WindowOptions::default(), |cx| cx.build_view(build_window)) } + pub fn add_window_view(&mut self, build_window: F) -> (View, VisualTestContext) + where + F: FnOnce(&mut ViewContext) -> V, + V: Render, + { + let mut cx = self.app.borrow_mut(); + let window = cx.open_window(WindowOptions::default(), |cx| cx.build_view(build_window)); + drop(cx); + let view = window.root_view(self).unwrap(); + (view, VisualTestContext::from_window(*window.deref(), self)) + } + pub fn spawn(&self, f: impl FnOnce(AsyncAppContext) -> Fut) -> Task where Fut: Future + 'static, @@ -158,7 +170,7 @@ impl TestAppContext { Some(read(lock.try_global()?, &lock)) } - pub fn set_global(&mut self, global: G) { + pub fn set_global(&mut self, global: G) { let mut lock = self.app.borrow_mut(); lock.set_global(global); } @@ -277,6 +289,72 @@ impl Model { } } +impl View { + pub fn condition( + &self, + cx: &TestAppContext, + mut predicate: impl FnMut(&V, &AppContext) -> bool, + ) -> impl Future + where + Evt: 'static, + V: EventEmitter, + { + use postage::prelude::{Sink as _, Stream as _}; + + let (tx, mut rx) = postage::mpsc::channel(1024); + let timeout_duration = Duration::from_millis(100); //todo!() cx.condition_duration(); + + let mut cx = cx.app.borrow_mut(); + let subscriptions = ( + cx.observe(self, { + let mut tx = tx.clone(); + move |_, _| { + tx.blocking_send(()).ok(); + } + }), + cx.subscribe(self, { + let mut tx = tx.clone(); + move |_, _: &Evt, _| { + tx.blocking_send(()).ok(); + } + }), + ); + + let cx = cx.this.upgrade().unwrap(); + let handle = self.downgrade(); + + async move { + crate::util::timeout(timeout_duration, async move { + loop { + { + let cx = cx.borrow(); + let cx = &*cx; + if predicate( + handle + .upgrade() + .expect("view dropped with pending condition") + .read(cx), + cx, + ) { + break; + } + } + + // todo!(start_waiting) + // cx.borrow().foreground_executor().start_waiting(); + rx.recv() + .await + .expect("view dropped with pending condition"); + // cx.borrow().foreground_executor().finish_waiting(); + } + }) + .await + .expect("condition timed out"); + drop(subscriptions); + } + } +} + use derive_more::{Deref, DerefMut}; #[derive(Deref, DerefMut)] pub struct VisualTestContext<'a> { diff --git a/crates/gpui2/src/color.rs b/crates/gpui2/src/color.rs index edf416ae7d..5f6308ec4f 100644 --- a/crates/gpui2/src/color.rs +++ b/crates/gpui2/src/color.rs @@ -167,7 +167,7 @@ impl TryFrom<&'_ str> for Rgba { } } -#[derive(Default, Copy, Clone, Debug, PartialEq, PartialOrd)] +#[derive(Default, Copy, Clone, Debug)] #[repr(C)] pub struct Hsla { pub h: f32, @@ -176,6 +176,35 @@ pub struct Hsla { pub a: f32, } +impl PartialEq for Hsla { + fn eq(&self, other: &Self) -> bool { + self.h + .total_cmp(&other.h) + .then(self.s.total_cmp(&other.s)) + .then(self.l.total_cmp(&other.l).then(self.a.total_cmp(&other.a))) + .is_eq() + } +} + +impl PartialOrd for Hsla { + fn partial_cmp(&self, other: &Self) -> Option { + // SAFETY: The total ordering relies on this always being Some() + Some( + self.h + .total_cmp(&other.h) + .then(self.s.total_cmp(&other.s)) + .then(self.l.total_cmp(&other.l).then(self.a.total_cmp(&other.a))), + ) + } +} + +impl Ord for Hsla { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + // SAFETY: The partial comparison is a total comparison + unsafe { self.partial_cmp(other).unwrap_unchecked() } + } +} + impl Hsla { pub fn to_rgb(self) -> Rgba { self.into() diff --git a/crates/gpui2/src/util.rs b/crates/gpui2/src/util.rs index 1000800881..3ee80306ea 100644 --- a/crates/gpui2/src/util.rs +++ b/crates/gpui2/src/util.rs @@ -1,16 +1,20 @@ +use std::time::Duration; + +use futures::Future; +use smol::future::FutureExt; pub use util::*; -// pub async fn timeout(timeout: Duration, f: F) -> Result -// where -// F: Future, -// { -// let timer = async { -// smol::Timer::after(timeout).await; -// Err(()) -// }; -// let future = async move { Ok(f.await) }; -// timer.race(future).await -// } +pub async fn timeout(timeout: Duration, f: F) -> Result +where + F: Future, +{ + let timer = async { + smol::Timer::after(timeout).await; + Err(()) + }; + let future = async move { Ok(f.await) }; + timer.race(future).await +} #[cfg(any(test, feature = "test-support"))] pub struct CwdBacktrace<'a>(pub &'a backtrace::Backtrace); diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index e4fc5d35c6..053b9d68af 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -4200,24 +4200,24 @@ impl ViewId { } } -// pub trait WorkspaceHandle { -// fn file_project_paths(&self, cx: &AppContext) -> Vec; -// } +pub trait WorkspaceHandle { + fn file_project_paths(&self, cx: &AppContext) -> Vec; +} -// impl WorkspaceHandle for View { -// fn file_project_paths(&self, cx: &AppContext) -> Vec { -// self.read(cx) -// .worktrees(cx) -// .flat_map(|worktree| { -// let worktree_id = worktree.read(cx).id(); -// worktree.read(cx).files(true, 0).map(move |f| ProjectPath { -// worktree_id, -// path: f.path.clone(), -// }) -// }) -// .collect::>() -// } -// } +impl WorkspaceHandle for View { + fn file_project_paths(&self, cx: &AppContext) -> Vec { + self.read(cx) + .worktrees(cx) + .flat_map(|worktree| { + let worktree_id = worktree.read(cx).id(); + worktree.read(cx).files(true, 0).map(move |f| ProjectPath { + worktree_id, + path: f.path.clone(), + }) + }) + .collect::>() + } +} // impl std::fmt::Debug for OpenPaths { // fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {