mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-19 10:29:35 +03:00
Avoid extra completion requests (#11875)
Do not spawn a second completion request when completion menu is open and a new edit is made. Release Notes: - N/A
This commit is contained in:
parent
e5a4421559
commit
4386268a94
@ -2041,6 +2041,7 @@ impl Editor {
|
||||
&mut self,
|
||||
local: bool,
|
||||
old_cursor_position: &Anchor,
|
||||
show_completions: bool,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
// Copy selections to primary selection buffer
|
||||
@ -2142,7 +2143,9 @@ impl Editor {
|
||||
})
|
||||
.detach();
|
||||
|
||||
self.show_completions(&ShowCompletions, cx);
|
||||
if show_completions {
|
||||
self.show_completions(&ShowCompletions, cx);
|
||||
}
|
||||
} else {
|
||||
drop(context_menu);
|
||||
self.hide_context_menu(cx);
|
||||
@ -2182,6 +2185,16 @@ impl Editor {
|
||||
autoscroll: Option<Autoscroll>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
|
||||
) -> R {
|
||||
self.change_selections_inner(autoscroll, true, cx, change)
|
||||
}
|
||||
|
||||
pub fn change_selections_inner<R>(
|
||||
&mut self,
|
||||
autoscroll: Option<Autoscroll>,
|
||||
request_completions: bool,
|
||||
cx: &mut ViewContext<Self>,
|
||||
change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
|
||||
) -> R {
|
||||
let old_cursor_position = self.selections.newest_anchor().head();
|
||||
self.push_to_selection_history();
|
||||
@ -2192,7 +2205,7 @@ impl Editor {
|
||||
if let Some(autoscroll) = autoscroll {
|
||||
self.request_autoscroll(autoscroll, cx);
|
||||
}
|
||||
self.selections_did_change(true, &old_cursor_position, cx);
|
||||
self.selections_did_change(true, &old_cursor_position, request_completions, cx);
|
||||
}
|
||||
|
||||
result
|
||||
@ -2852,7 +2865,9 @@ impl Editor {
|
||||
|
||||
drop(snapshot);
|
||||
let had_active_inline_completion = this.has_active_inline_completion(cx);
|
||||
this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
|
||||
this.change_selections_inner(Some(Autoscroll::fit()), false, cx, |s| {
|
||||
s.select(new_selections)
|
||||
});
|
||||
|
||||
if brace_inserted {
|
||||
// If we inserted a brace while composing text (i.e. typing `"` on a
|
||||
@ -9165,7 +9180,7 @@ impl Editor {
|
||||
s.clear_pending();
|
||||
}
|
||||
});
|
||||
self.selections_did_change(false, &old_cursor_position, cx);
|
||||
self.selections_did_change(false, &old_cursor_position, true, cx);
|
||||
}
|
||||
|
||||
fn push_to_selection_history(&mut self) {
|
||||
|
@ -6531,6 +6531,7 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
let counter = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
cx.set_state(indoc! {"
|
||||
oneˇ
|
||||
@ -6546,10 +6547,13 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||
three
|
||||
"},
|
||||
vec!["first_completion", "second_completion"],
|
||||
counter.clone(),
|
||||
)
|
||||
.await;
|
||||
cx.condition(|editor, _| editor.context_menu_visible())
|
||||
.await;
|
||||
assert_eq!(counter.load(atomic::Ordering::Acquire), 1);
|
||||
|
||||
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
||||
editor.context_menu_next(&Default::default(), cx);
|
||||
editor
|
||||
@ -6620,10 +6624,12 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||
additional edit
|
||||
"},
|
||||
vec!["fourth_completion", "fifth_completion", "sixth_completion"],
|
||||
counter.clone(),
|
||||
)
|
||||
.await;
|
||||
cx.condition(|editor, _| editor.context_menu_visible())
|
||||
.await;
|
||||
assert_eq!(counter.load(atomic::Ordering::Acquire), 2);
|
||||
|
||||
cx.simulate_keystroke("i");
|
||||
|
||||
@ -6636,10 +6642,12 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||
additional edit
|
||||
"},
|
||||
vec!["fourth_completion", "fifth_completion", "sixth_completion"],
|
||||
counter.clone(),
|
||||
)
|
||||
.await;
|
||||
cx.condition(|editor, _| editor.context_menu_visible())
|
||||
.await;
|
||||
assert_eq!(counter.load(atomic::Ordering::Acquire), 3);
|
||||
|
||||
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
||||
editor
|
||||
@ -6674,9 +6682,17 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.show_completions(&ShowCompletions, cx);
|
||||
});
|
||||
handle_completion_request(&mut cx, "editor.<clo|>", vec!["close", "clobber"]).await;
|
||||
handle_completion_request(
|
||||
&mut cx,
|
||||
"editor.<clo|>",
|
||||
vec!["close", "clobber"],
|
||||
counter.clone(),
|
||||
)
|
||||
.await;
|
||||
cx.condition(|editor, _| editor.context_menu_visible())
|
||||
.await;
|
||||
assert_eq!(counter.load(atomic::Ordering::Acquire), 4);
|
||||
|
||||
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
||||
editor
|
||||
.confirm_completion(&ConfirmCompletion::default(), cx)
|
||||
@ -6687,6 +6703,103 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||
apply_additional_edits.await.unwrap();
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_no_duplicated_completion_requests(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;
|
||||
|
||||
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("Some".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 counter = Arc::new(AtomicUsize::new(0));
|
||||
let counter_clone = counter.clone();
|
||||
let mut request = cx.handle_request::<lsp::request::Completion, _, _>(move |_, _, _| {
|
||||
let task_completion_item = closure_completion_item.clone();
|
||||
counter_clone.fetch_add(1, atomic::Ordering::Release);
|
||||
async move {
|
||||
Ok(Some(lsp::CompletionResponse::Array(vec![
|
||||
task_completion_item,
|
||||
])))
|
||||
}
|
||||
});
|
||||
|
||||
cx.condition(|editor, _| editor.context_menu_visible())
|
||||
.await;
|
||||
cx.assert_editor_state(indoc! {"fn main() { let a = 2.ˇ; }"});
|
||||
assert!(request.next().await.is_some());
|
||||
assert_eq!(counter.load(atomic::Ordering::Acquire), 1);
|
||||
|
||||
cx.simulate_keystroke("S");
|
||||
cx.simulate_keystroke("o");
|
||||
cx.simulate_keystroke("m");
|
||||
cx.condition(|editor, _| editor.context_menu_visible())
|
||||
.await;
|
||||
cx.assert_editor_state(indoc! {"fn main() { let a = 2.Somˇ; }"});
|
||||
assert!(request.next().await.is_some());
|
||||
assert!(request.next().await.is_some());
|
||||
assert!(request.next().await.is_some());
|
||||
request.close();
|
||||
assert!(request.next().await.is_none());
|
||||
assert_eq!(
|
||||
counter.load(atomic::Ordering::Acquire),
|
||||
4,
|
||||
"With the completions menu open, only one LSP request should happen per input"
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_toggle_comment(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
@ -11358,6 +11471,7 @@ pub fn handle_completion_request(
|
||||
cx: &mut EditorLspTestContext,
|
||||
marked_string: &str,
|
||||
completions: Vec<&'static str>,
|
||||
counter: Arc<AtomicUsize>,
|
||||
) -> impl Future<Output = ()> {
|
||||
let complete_from_marker: TextRangeMarker = '|'.into();
|
||||
let replace_range_marker: TextRangeMarker = ('<', '>').into();
|
||||
@ -11373,6 +11487,7 @@ pub fn handle_completion_request(
|
||||
|
||||
let mut request = cx.handle_request::<lsp::request::Completion, _, _>(move |url, params, _| {
|
||||
let completions = completions.clone();
|
||||
counter.fetch_add(1, atomic::Ordering::Release);
|
||||
async move {
|
||||
assert_eq!(params.text_document_position.text_document.uri, url.clone());
|
||||
assert_eq!(
|
||||
|
Loading…
Reference in New Issue
Block a user