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
2 changed files with 135 additions and 5 deletions
|
@ -2041,6 +2041,7 @@ impl Editor {
|
||||||
&mut self,
|
&mut self,
|
||||||
local: bool,
|
local: bool,
|
||||||
old_cursor_position: &Anchor,
|
old_cursor_position: &Anchor,
|
||||||
|
show_completions: bool,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
// Copy selections to primary selection buffer
|
// Copy selections to primary selection buffer
|
||||||
|
@ -2142,7 +2143,9 @@ impl Editor {
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
self.show_completions(&ShowCompletions, cx);
|
if show_completions {
|
||||||
|
self.show_completions(&ShowCompletions, cx);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
drop(context_menu);
|
drop(context_menu);
|
||||||
self.hide_context_menu(cx);
|
self.hide_context_menu(cx);
|
||||||
|
@ -2182,6 +2185,16 @@ impl Editor {
|
||||||
autoscroll: Option<Autoscroll>,
|
autoscroll: Option<Autoscroll>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
|
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 {
|
) -> R {
|
||||||
let old_cursor_position = self.selections.newest_anchor().head();
|
let old_cursor_position = self.selections.newest_anchor().head();
|
||||||
self.push_to_selection_history();
|
self.push_to_selection_history();
|
||||||
|
@ -2192,7 +2205,7 @@ impl Editor {
|
||||||
if let Some(autoscroll) = autoscroll {
|
if let Some(autoscroll) = autoscroll {
|
||||||
self.request_autoscroll(autoscroll, cx);
|
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
|
result
|
||||||
|
@ -2852,7 +2865,9 @@ impl Editor {
|
||||||
|
|
||||||
drop(snapshot);
|
drop(snapshot);
|
||||||
let had_active_inline_completion = this.has_active_inline_completion(cx);
|
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 brace_inserted {
|
||||||
// If we inserted a brace while composing text (i.e. typing `"` on a
|
// If we inserted a brace while composing text (i.e. typing `"` on a
|
||||||
|
@ -9165,7 +9180,7 @@ impl Editor {
|
||||||
s.clear_pending();
|
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) {
|
fn push_to_selection_history(&mut self) {
|
||||||
|
|
|
@ -6531,6 +6531,7 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
let counter = Arc::new(AtomicUsize::new(0));
|
||||||
|
|
||||||
cx.set_state(indoc! {"
|
cx.set_state(indoc! {"
|
||||||
oneˇ
|
oneˇ
|
||||||
|
@ -6546,10 +6547,13 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||||
three
|
three
|
||||||
"},
|
"},
|
||||||
vec!["first_completion", "second_completion"],
|
vec!["first_completion", "second_completion"],
|
||||||
|
counter.clone(),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
cx.condition(|editor, _| editor.context_menu_visible())
|
cx.condition(|editor, _| editor.context_menu_visible())
|
||||||
.await;
|
.await;
|
||||||
|
assert_eq!(counter.load(atomic::Ordering::Acquire), 1);
|
||||||
|
|
||||||
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
||||||
editor.context_menu_next(&Default::default(), cx);
|
editor.context_menu_next(&Default::default(), cx);
|
||||||
editor
|
editor
|
||||||
|
@ -6620,10 +6624,12 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||||
additional edit
|
additional edit
|
||||||
"},
|
"},
|
||||||
vec!["fourth_completion", "fifth_completion", "sixth_completion"],
|
vec!["fourth_completion", "fifth_completion", "sixth_completion"],
|
||||||
|
counter.clone(),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
cx.condition(|editor, _| editor.context_menu_visible())
|
cx.condition(|editor, _| editor.context_menu_visible())
|
||||||
.await;
|
.await;
|
||||||
|
assert_eq!(counter.load(atomic::Ordering::Acquire), 2);
|
||||||
|
|
||||||
cx.simulate_keystroke("i");
|
cx.simulate_keystroke("i");
|
||||||
|
|
||||||
|
@ -6636,10 +6642,12 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||||
additional edit
|
additional edit
|
||||||
"},
|
"},
|
||||||
vec!["fourth_completion", "fifth_completion", "sixth_completion"],
|
vec!["fourth_completion", "fifth_completion", "sixth_completion"],
|
||||||
|
counter.clone(),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
cx.condition(|editor, _| editor.context_menu_visible())
|
cx.condition(|editor, _| editor.context_menu_visible())
|
||||||
.await;
|
.await;
|
||||||
|
assert_eq!(counter.load(atomic::Ordering::Acquire), 3);
|
||||||
|
|
||||||
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
||||||
editor
|
editor
|
||||||
|
@ -6674,9 +6682,17 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||||
cx.update_editor(|editor, cx| {
|
cx.update_editor(|editor, cx| {
|
||||||
editor.show_completions(&ShowCompletions, 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())
|
cx.condition(|editor, _| editor.context_menu_visible())
|
||||||
.await;
|
.await;
|
||||||
|
assert_eq!(counter.load(atomic::Ordering::Acquire), 4);
|
||||||
|
|
||||||
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
||||||
editor
|
editor
|
||||||
.confirm_completion(&ConfirmCompletion::default(), cx)
|
.confirm_completion(&ConfirmCompletion::default(), cx)
|
||||||
|
@ -6687,6 +6703,103 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||||
apply_additional_edits.await.unwrap();
|
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]
|
#[gpui::test]
|
||||||
async fn test_toggle_comment(cx: &mut gpui::TestAppContext) {
|
async fn test_toggle_comment(cx: &mut gpui::TestAppContext) {
|
||||||
init_test(cx, |_| {});
|
init_test(cx, |_| {});
|
||||||
|
@ -11358,6 +11471,7 @@ pub fn handle_completion_request(
|
||||||
cx: &mut EditorLspTestContext,
|
cx: &mut EditorLspTestContext,
|
||||||
marked_string: &str,
|
marked_string: &str,
|
||||||
completions: Vec<&'static str>,
|
completions: Vec<&'static str>,
|
||||||
|
counter: Arc<AtomicUsize>,
|
||||||
) -> impl Future<Output = ()> {
|
) -> impl Future<Output = ()> {
|
||||||
let complete_from_marker: TextRangeMarker = '|'.into();
|
let complete_from_marker: TextRangeMarker = '|'.into();
|
||||||
let replace_range_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 mut request = cx.handle_request::<lsp::request::Completion, _, _>(move |url, params, _| {
|
||||||
let completions = completions.clone();
|
let completions = completions.clone();
|
||||||
|
counter.fetch_add(1, atomic::Ordering::Release);
|
||||||
async move {
|
async move {
|
||||||
assert_eq!(params.text_document_position.text_document.uri, url.clone());
|
assert_eq!(params.text_document_position.text_document.uri, url.clone());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue