1 //! This file provides snippet completions, like `pd` => `eprintln!(...)`.
3 use hir::Documentation;
4 use ide_db::helpers::{insert_use::ImportScope, SnippetCap};
8 context::PathCompletionContext, item::Builder, CompletionContext, CompletionItem,
9 CompletionItemKind, Completions, SnippetScope,
12 fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder {
13 let mut item = CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label);
14 item.insert_snippet(cap, snippet);
18 pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) {
19 if ctx.function_def.is_none() {
23 let can_be_stmt = match ctx.path_context {
24 Some(PathCompletionContext { is_trivial_path: true, can_be_stmt, .. }) => can_be_stmt,
28 let cap = match ctx.config.snippet_cap {
33 if !ctx.config.snippets.is_empty() {
34 add_custom_completions(acc, ctx, cap, SnippetScope::Expr);
38 snippet(ctx, cap, "pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc);
39 snippet(ctx, cap, "ppd", "eprintln!(\"$0 = {:#?}\", $0);").add_to(acc);
43 pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) {
44 if !ctx.expects_item()
45 || ctx.previous_token_is(T![unsafe])
46 || ctx.path_qual().is_some()
47 || ctx.has_impl_or_trait_prev_sibling()
51 if ctx.has_visibility_prev_sibling() {
52 return; // technically we could do some of these snippet completions if we were to put the
53 // attributes before the vis node.
55 let cap = match ctx.config.snippet_cap {
60 if !ctx.config.snippets.is_empty() {
61 add_custom_completions(acc, ctx, cap, SnippetScope::Item);
64 let mut item = snippet(
79 item.lookup_by("tmod");
82 let mut item = snippet(
85 "tfn (Test function)",
92 item.lookup_by("tfn");
95 let item = snippet(ctx, cap, "macro_rules", "macro_rules! $1 {\n\t($2) => {\n\t\t$0\n\t};\n}");
99 fn add_custom_completions(
100 acc: &mut Completions,
101 ctx: &CompletionContext,
106 ImportScope::find_insert_use_container_with_macros(&ctx.token.parent()?, &ctx.sema)?;
107 ctx.config.prefix_snippets().filter(|(_, snip)| snip.scope == scope).for_each(
109 let imports = match snip.imports(ctx, &import_scope) {
110 Some(imports) => imports,
113 let body = snip.snippet();
114 let mut builder = snippet(ctx, cap, &trigger, &body);
115 builder.documentation(Documentation::new(format!("```rust\n{}\n```", body)));
116 for import in imports.into_iter() {
117 builder.add_import(import);
119 builder.detail(snip.description.as_deref().unwrap_or_default());
129 tests::{check_edit_with_config, TEST_CONFIG},
130 CompletionConfig, Snippet,
134 fn custom_snippet_completion() {
135 check_edit_with_config(
137 snippets: vec![Snippet::new(
140 &["ControlFlow::Break(())".into()],
142 &["core::ops::ControlFlow".into()],
143 crate::SnippetScope::Expr,
154 use core::ops::ControlFlow;
156 fn main() { ControlFlow::Break(()) }