Trigger completion when typing words or trigger characters

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Max Brunsfeld 2022-01-31 16:50:51 -08:00
parent 8d2b7ba032
commit 1d1f8df180
6 changed files with 254 additions and 5 deletions

View file

@ -1253,6 +1253,7 @@ impl Editor {
self.insert(text, cx);
self.autoclose_pairs(cx);
self.end_transaction(cx);
self.trigger_completion_on_input(text, cx);
}
}
@ -1388,6 +1389,20 @@ impl Editor {
self.end_transaction(cx);
}
fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
if self.completion_state.is_none() {
if let Some(selection) = self.newest_anchor_selection() {
if self
.buffer
.read(cx)
.is_completion_trigger(selection.head(), text, cx)
{
self.show_completions(&ShowCompletions, cx);
}
}
}
}
fn autoclose_pairs(&mut self, cx: &mut ViewContext<Self>) {
let selections = self.local_selections::<usize>(cx);
let mut bracket_pair_state = None;
@ -4398,8 +4413,8 @@ pub fn char_kind(c: char) -> CharKind {
#[cfg(test)]
mod tests {
use super::*;
use language::LanguageConfig;
use std::{cell::RefCell, rc::Rc, time::Instant};
use language::{FakeFile, LanguageConfig};
use std::{cell::RefCell, path::Path, rc::Rc, time::Instant};
use text::Point;
use unindent::Unindent;
use util::test::sample_text;
@ -6456,6 +6471,95 @@ mod tests {
});
}
#[gpui::test]
async fn test_completion(mut cx: gpui::TestAppContext) {
let settings = cx.read(EditorSettings::test);
let (language_server, mut fake) = lsp::LanguageServer::fake_with_capabilities(
lsp::ServerCapabilities {
completion_provider: Some(lsp::CompletionOptions {
trigger_characters: Some(vec![".".to_string(), ":".to_string()]),
..Default::default()
}),
..Default::default()
},
cx.background(),
)
.await;
let text = "
one
two
three
"
.unindent();
let buffer = cx.add_model(|cx| {
Buffer::from_file(
0,
text,
Box::new(FakeFile {
path: Arc::from(Path::new("/the/file")),
}),
cx,
)
.with_language_server(language_server, cx)
});
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
let (_, editor) = cx.add_window(|cx| build_editor(buffer, settings, cx));
editor.update(&mut cx, |editor, cx| {
editor.select_ranges([3..3], None, cx);
editor.handle_input(&Input(".".to_string()), cx);
});
let (id, params) = fake.receive_request::<lsp::request::Completion>().await;
assert_eq!(
params.text_document_position.text_document.uri,
lsp::Url::from_file_path("/the/file").unwrap()
);
assert_eq!(
params.text_document_position.position,
lsp::Position::new(0, 4)
);
fake.respond(
id,
Some(lsp::CompletionResponse::Array(vec![
lsp::CompletionItem {
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
range: lsp::Range::new(lsp::Position::new(0, 4), lsp::Position::new(0, 4)),
new_text: "first_completion".to_string(),
})),
..Default::default()
},
lsp::CompletionItem {
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
range: lsp::Range::new(lsp::Position::new(0, 4), lsp::Position::new(0, 4)),
new_text: "second_completion".to_string(),
})),
..Default::default()
},
])),
)
.await;
editor.next_notification(&cx).await;
editor.update(&mut cx, |editor, cx| {
editor.move_down(&MoveDown, cx);
editor.confirm_completion(&ConfirmCompletion, cx);
assert_eq!(
editor.text(cx),
"
one.second_completion
two
three
"
.unindent()
);
});
}
#[gpui::test]
async fn test_toggle_comment(mut cx: gpui::TestAppContext) {
let settings = cx.read(EditorSettings::test);