mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-28 20:01:33 +00:00
Implement completion-resolution in editor2
Enable the completion tests in editor2.
This commit is contained in:
parent
2bd428102b
commit
9451bd605d
2 changed files with 486 additions and 492 deletions
|
@ -73,7 +73,7 @@ use ordered_float::OrderedFloat;
|
|||
use parking_lot::{Mutex, RwLock};
|
||||
use project::{FormatTrigger, Location, Project, ProjectPath, ProjectTransaction};
|
||||
use rand::prelude::*;
|
||||
use rpc::proto::*;
|
||||
use rpc::proto::{self, *};
|
||||
use scroll::{
|
||||
autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide,
|
||||
};
|
||||
|
@ -970,95 +970,94 @@ impl CompletionsMenu {
|
|||
|
||||
fn pre_resolve_completion_documentation(
|
||||
&self,
|
||||
_editor: &Editor,
|
||||
_cx: &mut ViewContext<Editor>,
|
||||
editor: &Editor,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> Option<Task<()>> {
|
||||
// todo!("implementation below ");
|
||||
None
|
||||
let settings = EditorSettings::get_global(cx);
|
||||
if !settings.show_completion_documentation {
|
||||
return None;
|
||||
}
|
||||
|
||||
let Some(project) = editor.project.clone() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let client = project.read(cx).client();
|
||||
let language_registry = project.read(cx).languages().clone();
|
||||
|
||||
let is_remote = project.read(cx).is_remote();
|
||||
let project_id = project.read(cx).remote_id();
|
||||
|
||||
let completions = self.completions.clone();
|
||||
let completion_indices: Vec<_> = self.matches.iter().map(|m| m.candidate_id).collect();
|
||||
|
||||
Some(cx.spawn(move |this, mut cx| async move {
|
||||
if is_remote {
|
||||
let Some(project_id) = project_id else {
|
||||
log::error!("Remote project without remote_id");
|
||||
return;
|
||||
};
|
||||
|
||||
for completion_index in completion_indices {
|
||||
let completions_guard = completions.read();
|
||||
let completion = &completions_guard[completion_index];
|
||||
if completion.documentation.is_some() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let server_id = completion.server_id;
|
||||
let completion = completion.lsp_completion.clone();
|
||||
drop(completions_guard);
|
||||
|
||||
Self::resolve_completion_documentation_remote(
|
||||
project_id,
|
||||
server_id,
|
||||
completions.clone(),
|
||||
completion_index,
|
||||
completion,
|
||||
client.clone(),
|
||||
language_registry.clone(),
|
||||
)
|
||||
.await;
|
||||
|
||||
_ = this.update(&mut cx, |_, cx| cx.notify());
|
||||
}
|
||||
} else {
|
||||
for completion_index in completion_indices {
|
||||
let completions_guard = completions.read();
|
||||
let completion = &completions_guard[completion_index];
|
||||
if completion.documentation.is_some() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let server_id = completion.server_id;
|
||||
let completion = completion.lsp_completion.clone();
|
||||
drop(completions_guard);
|
||||
|
||||
let server = project
|
||||
.read_with(&mut cx, |project, _| {
|
||||
project.language_server_for_id(server_id)
|
||||
})
|
||||
.ok()
|
||||
.flatten();
|
||||
let Some(server) = server else {
|
||||
return;
|
||||
};
|
||||
|
||||
Self::resolve_completion_documentation_local(
|
||||
server,
|
||||
completions.clone(),
|
||||
completion_index,
|
||||
completion,
|
||||
language_registry.clone(),
|
||||
)
|
||||
.await;
|
||||
|
||||
_ = this.update(&mut cx, |_, cx| cx.notify());
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
// {
|
||||
// let settings = EditorSettings::get_global(cx);
|
||||
// if !settings.show_completion_documentation {
|
||||
// return None;
|
||||
// }
|
||||
|
||||
// let Some(project) = editor.project.clone() else {
|
||||
// return None;
|
||||
// };
|
||||
|
||||
// let client = project.read(cx).client();
|
||||
// let language_registry = project.read(cx).languages().clone();
|
||||
|
||||
// let is_remote = project.read(cx).is_remote();
|
||||
// let project_id = project.read(cx).remote_id();
|
||||
|
||||
// let completions = self.completions.clone();
|
||||
// let completion_indices: Vec<_> = self.matches.iter().map(|m| m.candidate_id).collect();
|
||||
|
||||
// Some(cx.spawn(move |this, mut cx| async move {
|
||||
// if is_remote {
|
||||
// let Some(project_id) = project_id else {
|
||||
// log::error!("Remote project without remote_id");
|
||||
// return;
|
||||
// };
|
||||
|
||||
// for completion_index in completion_indices {
|
||||
// let completions_guard = completions.read();
|
||||
// let completion = &completions_guard[completion_index];
|
||||
// if completion.documentation.is_some() {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// let server_id = completion.server_id;
|
||||
// let completion = completion.lsp_completion.clone();
|
||||
// drop(completions_guard);
|
||||
|
||||
// Self::resolve_completion_documentation_remote(
|
||||
// project_id,
|
||||
// server_id,
|
||||
// completions.clone(),
|
||||
// completion_index,
|
||||
// completion,
|
||||
// client.clone(),
|
||||
// language_registry.clone(),
|
||||
// )
|
||||
// .await;
|
||||
|
||||
// _ = this.update(&mut cx, |_, cx| cx.notify());
|
||||
// }
|
||||
// } else {
|
||||
// for completion_index in completion_indices {
|
||||
// let completions_guard = completions.read();
|
||||
// let completion = &completions_guard[completion_index];
|
||||
// if completion.documentation.is_some() {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// let server_id = completion.server_id;
|
||||
// let completion = completion.lsp_completion.clone();
|
||||
// drop(completions_guard);
|
||||
|
||||
// let server = project.read_with(&mut cx, |project, _| {
|
||||
// project.language_server_for_id(server_id)
|
||||
// });
|
||||
// let Some(server) = server else {
|
||||
// return;
|
||||
// };
|
||||
|
||||
// Self::resolve_completion_documentation_local(
|
||||
// server,
|
||||
// completions.clone(),
|
||||
// completion_index,
|
||||
// completion,
|
||||
// language_registry.clone(),
|
||||
// )
|
||||
// .await;
|
||||
|
||||
// _ = this.update(&mut cx, |_, cx| cx.notify());
|
||||
// }
|
||||
// }
|
||||
// }))
|
||||
// }
|
||||
|
||||
fn attempt_resolve_selected_completion_documentation(
|
||||
&mut self,
|
||||
|
@ -1079,10 +1078,9 @@ impl CompletionsMenu {
|
|||
let completions = self.completions.clone();
|
||||
let completions_guard = completions.read();
|
||||
let completion = &completions_guard[completion_index];
|
||||
// todo!()
|
||||
// if completion.documentation.is_some() {
|
||||
// return;
|
||||
// }
|
||||
if completion.documentation.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
let server_id = completion.server_id;
|
||||
let completion = completion.lsp_completion.clone();
|
||||
|
@ -1141,41 +1139,40 @@ impl CompletionsMenu {
|
|||
client: Arc<Client>,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
) {
|
||||
// todo!()
|
||||
// let request = proto::ResolveCompletionDocumentation {
|
||||
// project_id,
|
||||
// language_server_id: server_id.0 as u64,
|
||||
// lsp_completion: serde_json::to_string(&completion).unwrap().into_bytes(),
|
||||
// };
|
||||
let request = proto::ResolveCompletionDocumentation {
|
||||
project_id,
|
||||
language_server_id: server_id.0 as u64,
|
||||
lsp_completion: serde_json::to_string(&completion).unwrap().into_bytes(),
|
||||
};
|
||||
|
||||
// let Some(response) = client
|
||||
// .request(request)
|
||||
// .await
|
||||
// .context("completion documentation resolve proto request")
|
||||
// .log_err()
|
||||
// else {
|
||||
// return;
|
||||
// };
|
||||
let Some(response) = client
|
||||
.request(request)
|
||||
.await
|
||||
.context("completion documentation resolve proto request")
|
||||
.log_err()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
// if response.text.is_empty() {
|
||||
// let mut completions = completions.write();
|
||||
// let completion = &mut completions[completion_index];
|
||||
// completion.documentation = Some(Documentation::Undocumented);
|
||||
// }
|
||||
if response.text.is_empty() {
|
||||
let mut completions = completions.write();
|
||||
let completion = &mut completions[completion_index];
|
||||
completion.documentation = Some(Documentation::Undocumented);
|
||||
}
|
||||
|
||||
// let documentation = if response.is_markdown {
|
||||
// Documentation::MultiLineMarkdown(
|
||||
// markdown::parse_markdown(&response.text, &language_registry, None).await,
|
||||
// )
|
||||
// } else if response.text.lines().count() <= 1 {
|
||||
// Documentation::SingleLine(response.text)
|
||||
// } else {
|
||||
// Documentation::MultiLinePlainText(response.text)
|
||||
// };
|
||||
let documentation = if response.is_markdown {
|
||||
Documentation::MultiLineMarkdown(
|
||||
markdown::parse_markdown(&response.text, &language_registry, None).await,
|
||||
)
|
||||
} else if response.text.lines().count() <= 1 {
|
||||
Documentation::SingleLine(response.text)
|
||||
} else {
|
||||
Documentation::MultiLinePlainText(response.text)
|
||||
};
|
||||
|
||||
// let mut completions = completions.write();
|
||||
// let completion = &mut completions[completion_index];
|
||||
// completion.documentation = Some(documentation);
|
||||
let mut completions = completions.write();
|
||||
let completion = &mut completions[completion_index];
|
||||
completion.documentation = Some(documentation);
|
||||
}
|
||||
|
||||
async fn resolve_completion_documentation_local(
|
||||
|
@ -1185,38 +1182,37 @@ impl CompletionsMenu {
|
|||
completion: lsp::CompletionItem,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
) {
|
||||
// todo!()
|
||||
// let can_resolve = server
|
||||
// .capabilities()
|
||||
// .completion_provider
|
||||
// .as_ref()
|
||||
// .and_then(|options| options.resolve_provider)
|
||||
// .unwrap_or(false);
|
||||
// if !can_resolve {
|
||||
// return;
|
||||
// }
|
||||
let can_resolve = server
|
||||
.capabilities()
|
||||
.completion_provider
|
||||
.as_ref()
|
||||
.and_then(|options| options.resolve_provider)
|
||||
.unwrap_or(false);
|
||||
if !can_resolve {
|
||||
return;
|
||||
}
|
||||
|
||||
// let request = server.request::<lsp::request::ResolveCompletionItem>(completion);
|
||||
// let Some(completion_item) = request.await.log_err() else {
|
||||
// return;
|
||||
// };
|
||||
let request = server.request::<lsp::request::ResolveCompletionItem>(completion);
|
||||
let Some(completion_item) = request.await.log_err() else {
|
||||
return;
|
||||
};
|
||||
|
||||
// if let Some(lsp_documentation) = completion_item.documentation {
|
||||
// let documentation = language::prepare_completion_documentation(
|
||||
// &lsp_documentation,
|
||||
// &language_registry,
|
||||
// None, // TODO: Try to reasonably work out which language the completion is for
|
||||
// )
|
||||
// .await;
|
||||
if let Some(lsp_documentation) = completion_item.documentation {
|
||||
let documentation = language::prepare_completion_documentation(
|
||||
&lsp_documentation,
|
||||
&language_registry,
|
||||
None, // TODO: Try to reasonably work out which language the completion is for
|
||||
)
|
||||
.await;
|
||||
|
||||
// let mut completions = completions.write();
|
||||
// let completion = &mut completions[completion_index];
|
||||
// completion.documentation = Some(documentation);
|
||||
// } else {
|
||||
// let mut completions = completions.write();
|
||||
// let completion = &mut completions[completion_index];
|
||||
// completion.documentation = Some(Documentation::Undocumented);
|
||||
// }
|
||||
let mut completions = completions.write();
|
||||
let completion = &mut completions[completion_index];
|
||||
completion.documentation = Some(documentation);
|
||||
} else {
|
||||
let mut completions = completions.write();
|
||||
let completion = &mut completions[completion_index];
|
||||
completion.documentation = Some(Documentation::Undocumented);
|
||||
}
|
||||
}
|
||||
|
||||
fn visible(&self) -> bool {
|
||||
|
|
|
@ -5427,178 +5427,177 @@ async fn test_strip_whitespace_and_format_via_lsp(cx: &mut gpui::TestAppContext)
|
|||
);
|
||||
}
|
||||
|
||||
//todo!(completion)
|
||||
// #[gpui::test]
|
||||
// async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||
// init_test(cx, |_| {});
|
||||
#[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 <s|>
|
||||
// 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 <s|>
|
||||
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 <si|>
|
||||
// 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 <si|>
|
||||
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::<SettingsStore, _, _>(|settings, cx| {
|
||||
// settings.update_user_settings::<EditorSettings>(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.<clo|>", 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::<SettingsStore, _>(|settings, cx| {
|
||||
settings.update_user_settings::<EditorSettings>(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.<clo|>", 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) {
|
||||
|
@ -7803,197 +7802,196 @@ async fn test_language_server_restart_due_to_settings_change(cx: &mut gpui::Test
|
|||
);
|
||||
}
|
||||
|
||||
//todo!(completions)
|
||||
// #[gpui::test]
|
||||
// async fn test_completions_with_additional_edits(cx: &mut gpui::TestAppContext) {
|
||||
// init_test(cx, |_| {});
|
||||
#[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::<lsp::request::Completion, _, _>(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::<lsp::request::Completion, _, _>(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::<lsp::request::ResolveCompletionItem, _, _>(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::<lsp::request::ResolveCompletionItem, _, _>(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::<lsp::request::Completion, _, _>(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::<lsp::request::Completion, _, _>(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#"<p class="bgˇ" />"#);
|
||||
cx.set_state(r#"<p class="bgˇ" />"#);
|
||||
|
||||
// // 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::<Vec<_>>(),
|
||||
// &["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::<Vec<_>>(),
|
||||
&["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::<Vec<_>>(),
|
||||
// &["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::<Vec<_>>(),
|
||||
&["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#"<p class="yelˇ" />"#);
|
||||
// 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::<Vec<_>>(),
|
||||
// &["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#"<p class="yelˇ" />"#);
|
||||
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::<Vec<_>>(),
|
||||
&["bg-yellow"]
|
||||
);
|
||||
} else {
|
||||
panic!("expected completion menu to be open");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_document_format_with_prettier(cx: &mut gpui::TestAppContext) {
|
||||
|
|
Loading…
Reference in a new issue