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