From 625beaaa9b34b16a32fe2a0e00486e5fdf84c67f Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 4 Feb 2022 15:47:01 +0100 Subject: [PATCH] Finish writing test for the new autocompletion behavior Co-Authored-By: Nathan Sobo --- crates/editor/src/editor.rs | 83 +++++++++++++++++++++++++++++++------ crates/gpui/src/executor.rs | 34 +++++++++++---- 2 files changed, 97 insertions(+), 20 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 926369093e..045fb49b75 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -4000,7 +4000,8 @@ impl Editor { if kind == Some(CharKind::Word) && word_range.to_inclusive().contains(&cursor_position) { let query = Self::completion_query(&buffer, cursor_position); - smol::block_on(completion_state.filter(query.as_deref(), cx.background().clone())); + cx.background() + .block(completion_state.filter(query.as_deref(), cx.background().clone())); self.show_completions(&ShowCompletions, cx); } else { self.hide_completions(cx); @@ -7133,15 +7134,7 @@ mod tests { let (_, editor) = cx.add_window(|cx| build_editor(buffer, settings, cx)); editor.update(&mut cx, |editor, cx| { - editor.select_ranges( - [ - Point::new(0, 3)..Point::new(0, 3), - Point::new(1, 3)..Point::new(1, 3), - Point::new(2, 3)..Point::new(2, 3), - ], - None, - cx, - ); + editor.select_ranges([Point::new(0, 3)..Point::new(0, 3)], None, cx); editor.handle_input(&Input(".".to_string()), cx); }); @@ -7150,8 +7143,8 @@ mod tests { "/the/file", Point::new(0, 4), &[ - (Point::new(0, 4)..Point::new(0, 4), "first completion"), - (Point::new(0, 4)..Point::new(0, 4), "second completion"), + (Point::new(0, 4)..Point::new(0, 4), "first_completion"), + (Point::new(0, 4)..Point::new(0, 4), "second_completion"), ], ) .await; @@ -7189,6 +7182,71 @@ mod tests { .unindent() ); + editor.update(&mut cx, |editor, cx| { + editor.select_ranges( + [ + Point::new(1, 3)..Point::new(1, 3), + Point::new(2, 5)..Point::new(2, 5), + ], + None, + cx, + ); + + editor.handle_input(&Input(" ".to_string()), cx); + assert!(editor.completion_state.is_none()); + editor.handle_input(&Input("s".to_string()), cx); + assert!(editor.completion_state.is_none()); + }); + + handle_completion_request( + &mut fake, + "/the/file", + Point::new(2, 7), + &[ + (Point::new(2, 6)..Point::new(2, 7), "fourth_completion"), + (Point::new(2, 6)..Point::new(2, 7), "fifth_completion"), + (Point::new(2, 6)..Point::new(2, 7), "sixth_completion"), + ], + ) + .await; + editor + .condition(&cx, |editor, _| editor.completion_state.is_some()) + .await; + + editor.update(&mut cx, |editor, cx| { + editor.handle_input(&Input("i".to_string()), cx); + }); + + handle_completion_request( + &mut fake, + "/the/file", + Point::new(2, 8), + &[ + (Point::new(2, 6)..Point::new(2, 8), "fourth_completion"), + (Point::new(2, 6)..Point::new(2, 8), "fifth_completion"), + (Point::new(2, 6)..Point::new(2, 8), "sixth_completion"), + ], + ) + .await; + editor.next_notification(&cx).await; + + let apply_additional_edits = editor.update(&mut cx, |editor, cx| { + let apply_additional_edits = editor.confirm_completion(None, cx).unwrap(); + assert_eq!( + editor.text(cx), + " + one.second_completion + two sixth_completion + three sixth_completion + additional edit + " + .unindent() + ); + apply_additional_edits + }); + handle_resolve_completion_request(&mut fake, None).await; + apply_additional_edits.await.unwrap(); + async fn handle_completion_request( fake: &mut FakeLanguageServer, path: &str, @@ -7208,6 +7266,7 @@ mod tests { let completions = completions .iter() .map(|(range, new_text)| lsp::CompletionItem { + label: new_text.to_string(), text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { range: lsp::Range::new( lsp::Position::new(range.start.row, range.start.column), diff --git a/crates/gpui/src/executor.rs b/crates/gpui/src/executor.rs index 5e37acbc1d..8021391978 100644 --- a/crates/gpui/src/executor.rs +++ b/crates/gpui/src/executor.rs @@ -236,16 +236,14 @@ impl Deterministic { } } - fn block_on(&self, future: &mut AnyLocalFuture) -> Option> { + fn block(&self, future: &mut F, max_ticks: usize) -> Option + where + F: Unpin + Future, + { let unparker = self.parker.lock().unparker(); let waker = waker_fn(move || { unparker.unpark(); }); - let max_ticks = { - let mut state = self.state.lock(); - let range = state.block_on_ticks.clone(); - state.rng.gen_range(range) - }; let mut cx = Context::from_waker(&waker); for _ in 0..max_ticks { @@ -258,7 +256,7 @@ impl Deterministic { runnable.run(); } else { drop(state); - if let Poll::Ready(result) = future.as_mut().poll(&mut cx) { + if let Poll::Ready(result) = future.poll(&mut cx) { return Some(result); } let mut state = self.state.lock(); @@ -488,6 +486,19 @@ impl Background { Task::send(any_task) } + pub fn block(&self, future: F) -> T + where + F: Future, + { + smol::pin!(future); + match self { + Self::Production { .. } => smol::block_on(&mut future), + Self::Deterministic { executor, .. } => { + executor.block(&mut future, usize::MAX).unwrap() + } + } + } + pub fn block_with_timeout( &self, timeout: Duration, @@ -501,7 +512,14 @@ impl Background { if !timeout.is_zero() { let output = match self { Self::Production { .. } => smol::block_on(util::timeout(timeout, &mut future)).ok(), - Self::Deterministic { executor, .. } => executor.block_on(&mut future), + Self::Deterministic { executor, .. } => { + let max_ticks = { + let mut state = executor.state.lock(); + let range = state.block_on_ticks.clone(); + state.rng.gen_range(range) + }; + executor.block(&mut future, max_ticks) + } }; if let Some(output) = output { return Ok(*output.downcast().unwrap());