mirror of
https://github.com/zed-industries/zed.git
synced 2026-07-09 16:00:35 +00:00
editor: Fix showing completion list with selection does not include the selection (#57405)
Fix the completion list not showing the current selection when you execute `editor: show completions`, the stated reason by comment before is that if you are in a tabstop snippet already it wont give you the correct options. So my change is to just check if you are in such a snippet and if not give the new desired behavior. before: https://github.com/user-attachments/assets/1b2f3594-7361-4636-9ef3-f8c9419faa26 after: https://github.com/user-attachments/assets/1be35582-464a-40f3-b6be-ee74f9961796 Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Closes #57386 Release Notes: - editor: include text from selection in completion list. --------- Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
This commit is contained in:
parent
8036a3c74b
commit
e990f31ad7
2 changed files with 110 additions and 9 deletions
|
|
@ -266,14 +266,20 @@ impl Editor {
|
|||
|
||||
let multibuffer_snapshot = self.buffer.read(cx).read(cx);
|
||||
|
||||
// Typically `start` == `end`, but with snippet tabstop choices the default choice is
|
||||
// inserted and selected. To handle that case, the start of the selection is used so that
|
||||
// the menu starts with all choices.
|
||||
let position = self
|
||||
.selections
|
||||
.newest_anchor()
|
||||
.start
|
||||
.bias_right(&multibuffer_snapshot);
|
||||
let is_showing_snippet_choices = matches!(
|
||||
completions_source,
|
||||
Some(CompletionsMenuSource::SnippetChoices)
|
||||
);
|
||||
|
||||
let anchor = self.selections.newest_anchor();
|
||||
let position = if is_showing_snippet_choices {
|
||||
// Typically `start` == `end`, but with snippet tabstop choices the default choice is
|
||||
// inserted and selected. To handle that case, the start of the selection is used so that
|
||||
// the menu starts with all choices.
|
||||
anchor.start.bias_right(&multibuffer_snapshot)
|
||||
} else {
|
||||
anchor.head().bias_right(&multibuffer_snapshot)
|
||||
};
|
||||
|
||||
if position.diff_base_anchor().is_some() {
|
||||
return;
|
||||
|
|
@ -315,7 +321,7 @@ impl Editor {
|
|||
|
||||
// Hide the current completions menu when query is empty. Without this, cached
|
||||
// completions from before the trigger char may be reused (#32774).
|
||||
if query.is_none() && menu_is_open {
|
||||
if query.is_none() && menu_is_open && !is_showing_snippet_choices {
|
||||
self.hide_context_menu(window, cx);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13732,6 +13732,49 @@ async fn test_snippet_placeholder_choices(cx: &mut TestAppContext) {
|
|||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_snippet_choices_menu_survives_completion_refresh(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
let (text, insertion_ranges) = marked_text_ranges(
|
||||
indoc! {"
|
||||
ˇ
|
||||
"},
|
||||
false,
|
||||
);
|
||||
|
||||
let buffer = cx.update(|cx| MultiBuffer::build_simple(&text, cx));
|
||||
let (editor, cx) = cx.add_window_view(|window, cx| build_editor(buffer, window, cx));
|
||||
|
||||
_ = editor.update_in(cx, |editor, window, cx| {
|
||||
let snippet = Snippet::parse("type ${1|i32,u32|} = $2").unwrap();
|
||||
|
||||
editor
|
||||
.insert_snippet(
|
||||
&insertion_ranges
|
||||
.iter()
|
||||
.map(|range| MultiBufferOffset(range.start)..MultiBufferOffset(range.end))
|
||||
.collect::<Vec<_>>(),
|
||||
snippet,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
editor.context_menu_visible(),
|
||||
"Snippet choices menu should be visible after inserting the choice tabstop"
|
||||
);
|
||||
|
||||
editor.open_or_update_completions_menu(None, None, false, window, cx);
|
||||
|
||||
assert!(
|
||||
editor.context_menu_visible(),
|
||||
"Snippet choices menu should remain visible after a completion refresh with an empty query"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_snippet_tabstop_navigation_with_placeholders(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
|
@ -18359,6 +18402,58 @@ async fn test_word_completions_continue_on_typing(cx: &mut TestAppContext) {
|
|||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_completions_use_selection_head(cx: &mut TestAppContext) {
|
||||
init_test(cx, |language_settings| {
|
||||
language_settings.defaults.completions = Some(CompletionSettingsContent {
|
||||
words: Some(WordsCompletionMode::Disabled),
|
||||
words_min_length: Some(0),
|
||||
lsp_insert_mode: Some(LspInsertMode::Insert),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
let mut cx = EditorLspTestContext::new_rust(
|
||||
lsp::ServerCapabilities {
|
||||
completion_provider: Some(lsp::CompletionOptions::default()),
|
||||
..lsp::ServerCapabilities::default()
|
||||
},
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
|
||||
let _completion_requests_handler =
|
||||
cx.lsp
|
||||
.server
|
||||
.on_request::<lsp::request::Completion, _, _>(move |_, _| async move {
|
||||
panic!("LSP completions should not be queried when dealing with word completions")
|
||||
});
|
||||
|
||||
cx.set_state(indoc! {"«applˇ»
|
||||
applepie
|
||||
banana
|
||||
cherry
|
||||
"});
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor.show_word_completions(&ShowWordCompletions, window, cx);
|
||||
});
|
||||
cx.executor().run_until_parked();
|
||||
cx.condition(|editor, _| editor.context_menu_visible())
|
||||
.await;
|
||||
cx.update_editor(|editor, _, _| {
|
||||
if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref()
|
||||
{
|
||||
assert_eq!(
|
||||
completion_menu_entries(menu),
|
||||
&["applepie"],
|
||||
"Completion query should use the selection head (`appl`), filtering to words with that prefix"
|
||||
);
|
||||
} else {
|
||||
panic!("expected completion menu to be open");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_word_completions_usually_skip_digits(cx: &mut TestAppContext) {
|
||||
init_test(cx, |language_settings| {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue