diff --git a/crates/agent_ui/src/acp/message_editor.rs b/crates/agent_ui/src/acp/message_editor.rs index be1c205cee661d401d577b0bcb2d50dc62b4e38c..6069c22d1bfa4abb6acd2d74fab8646136480517 100644 --- a/crates/agent_ui/src/acp/message_editor.rs +++ b/crates/agent_ui/src/acp/message_editor.rs @@ -1671,6 +1671,7 @@ mod tests { trigger_kind: CompletionTriggerKind::TRIGGER_CHARACTER, trigger_character: Some("@".into()), }, + false, window, cx, ) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 635207de1a630c895e7bd12898356a353ca14c50..7673a9526ff095d5d63ef23df858bd718e0b5500 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -23009,7 +23009,7 @@ fn snippet_completions( }); } - for snippets in scopes.into_iter() { + for (_scope, snippets) in scopes.into_iter() { // Sort snippets by word count to match longer snippet prefixes first. let mut sorted_snippet_candidates = snippets .iter() diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index fcc05dbbc36dc275a8a01eea00bdcdf81869b872..0b260d006cbe161b2b54fe62d9d0a48f822bc3b9 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -11083,6 +11083,50 @@ async fn test_snippet_indentation(cx: &mut TestAppContext) { ˇ"}); } +#[gpui::test] +async fn test_snippet_with_multi_word_prefix(cx: &mut TestAppContext) { + init_test(cx, |_| {}); + + let mut cx = EditorTestContext::new(cx).await; + cx.update_editor(|editor, window, cx| { + editor.project().unwrap().update(cx, |project, cx| { + project.snippets().update(cx, |snippets, cx| { + let snippet = project::snippet_provider::Snippet { + prefix: "multi word".to_string(), + body: "this is many words".to_string(), + description: "description".to_string(), + name: "multi-word snippet test".to_string(), + }; + snippets.add_snippet_for_test( + None, + PathBuf::from("test_snippets.json"), + vec![Arc::new(snippet)], + cx, + ); + }); + }) + }); + + cx.set_state("mˇ"); + cx.simulate_input("u"); + + cx.update_editor(|editor, window, cx| { + let CodeContextMenu::Completions(context_menu) = editor.context_menu.borrow().unwrap() + else { + panic!("expected completion menu") + }; + assert!(context_menu.visible()); + let completions = context_menu; + + assert!( + completions + .iter() + .any(|c| c.string.as_str() == "multi word"), + "Expected to find 'multi word' snippet in completions" + ); + }); +} + #[gpui::test] async fn test_document_format_during_save(cx: &mut TestAppContext) { init_test(cx, |_| {}); @@ -13584,7 +13628,14 @@ async fn test_completion_mode(cx: &mut TestAppContext) { cx.set_state(&run.initial_state); cx.update_editor(|editor, window, cx| { - editor.show_completions(&ShowCompletions { trigger: None }, window, cx); + editor.show_completions( + &ShowCompletions { + trigger: None, + snippets_only: false, + }, + window, + cx, + ); }); let counter = Arc::new(AtomicUsize::new(0)); diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index 39dc0621732bfd42b3a24735ad803915fbf2885c..fc2c04b23ae3f5fd63db9bd4700e55c0faaab2c8 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -18,6 +18,7 @@ test-support = [ "client/test-support", "language/test-support", "settings/test-support", + "snippet_provider/test-support", "text/test-support", "prettier/test-support", "worktree/test-support", @@ -109,6 +110,7 @@ pretty_assertions.workspace = true release_channel.workspace = true rpc = { workspace = true, features = ["test-support"] } settings = { workspace = true, features = ["test-support"] } +snippet_provider = { workspace = true, features = ["test-support"] } unindent.workspace = true util = { workspace = true, features = ["test-support"] } worktree = { workspace = true, features = ["test-support"] } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 4fed6be0ef3eb8eeb587015df323f00864bd95ea..0c18306119a6c27faf34748ce98f21824b3038b3 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -105,6 +105,7 @@ use search_history::SearchHistory; use settings::{InvalidSettingsError, Settings, SettingsLocation, SettingsStore}; use smol::channel::Receiver; use snippet::Snippet; +pub use snippet_provider; use snippet_provider::SnippetProvider; use std::{ borrow::Cow, diff --git a/crates/snippet_provider/Cargo.toml b/crates/snippet_provider/Cargo.toml index af7ffcf30ef71a21a6cdfd2efaf1ce3cf763016b..6452d2e7e100e8bd516b571c139c5f28987146fe 100644 --- a/crates/snippet_provider/Cargo.toml +++ b/crates/snippet_provider/Cargo.toml @@ -8,6 +8,9 @@ license = "GPL-3.0-or-later" [lints] workspace = true +[features] +test-support = [] + [dependencies] anyhow.workspace = true collections.workspace = true diff --git a/crates/snippet_provider/src/lib.rs b/crates/snippet_provider/src/lib.rs index eac06924a7906aba08d90c0d1c3d1f1743531954..2af740483157c69e651246d000600c5e2ef88aa6 100644 --- a/crates/snippet_provider/src/lib.rs +++ b/crates/snippet_provider/src/lib.rs @@ -235,6 +235,20 @@ impl SnippetProvider { user_snippets } + #[cfg(any(test, feature = "test-support"))] + pub fn add_snippet_for_test( + &mut self, + language: SnippetKind, + path: PathBuf, + snippet: Vec>, + cx: &mut Context, + ) { + self.snippets + .entry(language) + .or_default() + .insert(path, snippet); + } + pub fn snippets_for(&self, language: SnippetKind, cx: &App) -> Vec> { let mut requested_snippets = self.lookup_snippets::(&language, cx);