ide_completion/completions/postfix/
format_like.rs1use ide_db::{
20 SnippetCap,
21 source_change::SnippetEdit,
22 syntax_helpers::format_string_exprs::{Arg, parse_format_exprs, with_placeholders},
23};
24use syntax::{AstToken, ast};
25
26use crate::{
27 Completions, completions::postfix::build_postfix_snippet_builder, context::CompletionContext,
28};
29
30static KINDS: &[(&str, &str)] = &[
32 ("format", "format!"),
33 ("panic", "panic!"),
34 ("println", "println!"),
35 ("eprintln", "eprintln!"),
36 ("logd", "log::debug!"),
37 ("logt", "log::trace!"),
38 ("logi", "log::info!"),
39 ("logw", "log::warn!"),
40 ("loge", "log::error!"),
41];
42static SNIPPET_RETURNS_NON_UNIT: &[&str] = &["format"];
43
44pub(crate) fn add_format_like_completions(
45 acc: &mut Completions,
46 ctx: &CompletionContext<'_, '_>,
47 dot_receiver: &ast::Expr,
48 cap: SnippetCap,
49 receiver_text: &ast::String,
50 semi: &str,
51) {
52 let postfix_snippet = match build_postfix_snippet_builder(ctx, cap, dot_receiver) {
53 Some(it) => it,
54 None => return,
55 };
56
57 if let Ok((mut out, mut exprs)) = parse_format_exprs(receiver_text.text()) {
58 SnippetEdit::escape_snippet_bits(&mut out);
60 for arg in &mut exprs {
61 if let Arg::Ident(text) | Arg::Expr(text) = arg {
62 SnippetEdit::escape_snippet_bits(text)
63 }
64 }
65
66 let exprs = with_placeholders(exprs);
67 for (label, macro_name) in KINDS {
68 let semi = if SNIPPET_RETURNS_NON_UNIT.contains(label) { "" } else { semi };
69 let snippet = if exprs.is_empty() {
70 format!(r#"{macro_name}({out}){semi}"#)
71 } else {
72 format!(r#"{}({}, {}){semi}"#, macro_name, out, exprs.join(", "))
73 };
74
75 postfix_snippet(label, macro_name, snippet).add_to(acc, ctx.db);
76 }
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn test_into_suggestion() {
86 let test_vector = &[
87 ("println!", "{}", r#"println!("{}", $1)"#),
88 ("eprintln!", "{}", r#"eprintln!("{}", $1)"#),
89 (
90 "log::info!",
91 "{} {ident} {} {2 + 2}",
92 r#"log::info!("{} {ident} {} {}", $1, $2, 2 + 2)"#,
93 ),
94 ];
95
96 for (kind, input, output) in test_vector {
97 let (parsed_string, exprs) = parse_format_exprs(input).unwrap();
98 let exprs = with_placeholders(exprs);
99 let snippet = format!(r#"{kind}("{parsed_string}", {})"#, exprs.join(", "));
100 assert_eq!(&snippet, output);
101 }
102 }
103
104 #[test]
105 fn test_into_suggestion_no_epxrs() {
106 let test_vector = &[
107 ("println!", "{ident}", r#"println!("{ident}")"#),
108 ("format!", "{ident:?}", r#"format!("{ident:?}")"#),
109 ];
110
111 for (kind, input, output) in test_vector {
112 let (parsed_string, _exprs) = parse_format_exprs(input).unwrap();
113 let snippet = format!(r#"{kind}("{parsed_string}")"#);
114 assert_eq!(&snippet, output);
115 }
116 }
117}