1 //! Completes identifiers in format string literals.
3 use ide_db::syntax_helpers::format_string::is_format_string;
4 use itertools::Itertools;
5 use syntax::{ast, AstToken, TextRange, TextSize};
7 use crate::{context::CompletionContext, CompletionItem, CompletionItemKind, Completions};
9 /// Complete identifiers in format strings.
10 pub(crate) fn format_string(
11 acc: &mut Completions,
12 ctx: &CompletionContext<'_>,
13 original: &ast::String,
14 expanded: &ast::String,
16 if !is_format_string(&expanded) {
19 let cursor = ctx.position.offset;
20 let lit_start = ctx.original_token.text_range().start();
21 let cursor_in_lit = cursor - lit_start;
23 let prefix = &original.text()[..cursor_in_lit.into()];
24 let braces = prefix.char_indices().rev().skip_while(|&(_, c)| c.is_alphanumeric()).next_tuple();
25 let brace_offset = match braces {
27 Some(((_, '{'), (_, '{'))) => return,
28 Some(((idx, '{'), _)) => lit_start + TextSize::from(idx as u32 + 1),
32 let source_range = TextRange::new(brace_offset, cursor);
33 ctx.locals.iter().for_each(|(name, _)| {
34 CompletionItem::new(CompletionItemKind::Binding, source_range, name.to_smol_str())
41 use expect_test::{expect, Expect};
43 use crate::tests::{check_edit, completion_list_no_kw};
45 fn check(ra_fixture: &str, expect: Expect) {
46 let actual = completion_list_no_kw(ra_fixture);
47 expect.assert_eq(&actual);
51 fn works_when_wrapped() {
54 macro_rules! format_args {
55 ($lit:literal $(tt:tt)*) => { 0 },
58 ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
70 fn no_completion_without_brace() {
73 macro_rules! format_args {
74 ($lit:literal $(tt:tt)*) => { 0 },
86 fn completes_locals() {
90 macro_rules! format_args {
91 ($lit:literal $(tt:tt)*) => { 0 },
99 macro_rules! format_args {
100 ($lit:literal $(tt:tt)*) => { 0 },
104 format_args!("{foobar");
111 macro_rules! format_args {
112 ($lit:literal $(tt:tt)*) => { 0 },
120 macro_rules! format_args {
121 ($lit:literal $(tt:tt)*) => { 0 },
125 format_args!("{foobar");