Skip to content

Commit d307bc6

Browse files
Merge pull request rust-lang#20418 from A4-Tacks/fix-extract-expr-from-fmtstr-on-write
Fix extract_expressions_from_format_string on write!
2 parents 29cb5d4 + 62508aa commit d307bc6

File tree

1 file changed

+40
-6
lines changed

1 file changed

+40
-6
lines changed

crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use itertools::Itertools;
77
use syntax::{
88
AstNode, AstToken, NodeOrToken,
99
SyntaxKind::WHITESPACE,
10-
T,
11-
ast::{self, make, syntax_factory::SyntaxFactory},
10+
SyntaxToken, T,
11+
ast::{self, TokenTree, make, syntax_factory::SyntaxFactory},
1212
};
1313

1414
// Assist: extract_expressions_from_format_string
@@ -58,10 +58,11 @@ pub(crate) fn extract_expressions_from_format_string(
5858
tt.syntax().text_range(),
5959
|edit| {
6060
// Extract existing arguments in macro
61-
let tokens = tt.token_trees_and_tokens().collect_vec();
61+
let mut raw_tokens = tt.token_trees_and_tokens().skip(1).collect_vec();
62+
let format_string_index = format_str_index(&raw_tokens, &fmt_string);
63+
let tokens = raw_tokens.split_off(format_string_index);
6264

6365
let existing_args = if let [
64-
_opening_bracket,
6566
NodeOrToken::Token(_format_string),
6667
_args_start_comma,
6768
tokens @ ..,
@@ -90,9 +91,11 @@ pub(crate) fn extract_expressions_from_format_string(
9091

9192
// Start building the new args
9293
let mut existing_args = existing_args.into_iter();
93-
let mut new_tt_bits = vec![NodeOrToken::Token(make::tokens::literal(&new_fmt))];
94+
let mut new_tt_bits = raw_tokens;
9495
let mut placeholder_indexes = vec![];
9596

97+
new_tt_bits.push(NodeOrToken::Token(make::tokens::literal(&new_fmt)));
98+
9699
for arg in extracted_args {
97100
if matches!(arg, Arg::Expr(_) | Arg::Placeholder) {
98101
// insert ", " before each arg
@@ -150,7 +153,9 @@ pub(crate) fn extract_expressions_from_format_string(
150153
}
151154

152155
// Add the final tabstop after the format literal
153-
if let Some(NodeOrToken::Token(literal)) = new_tt.token_trees_and_tokens().nth(1) {
156+
if let Some(NodeOrToken::Token(literal)) =
157+
new_tt.token_trees_and_tokens().nth(1 + format_string_index)
158+
{
154159
let annotation = edit.make_tabstop_after(cap);
155160
editor.add_annotation(literal, annotation);
156161
}
@@ -163,6 +168,17 @@ pub(crate) fn extract_expressions_from_format_string(
163168
Some(())
164169
}
165170

171+
fn format_str_index(
172+
raw_tokens: &[NodeOrToken<TokenTree, SyntaxToken>],
173+
fmt_string: &ast::String,
174+
) -> usize {
175+
let fmt_string = fmt_string.syntax();
176+
raw_tokens
177+
.iter()
178+
.position(|tt| tt.as_token().is_some_and(|tt| tt == fmt_string))
179+
.unwrap_or_default()
180+
}
181+
166182
#[cfg(test)]
167183
mod tests {
168184
use super::*;
@@ -186,6 +202,24 @@ fn main() {
186202
);
187203
}
188204

205+
#[test]
206+
fn multiple_middle_arg_on_write() {
207+
check_assist(
208+
extract_expressions_from_format_string,
209+
r#"
210+
//- minicore: write
211+
fn main() {
212+
write!(writer(), "{} {x + 1:b} {}$0", y + 2, 2);
213+
}
214+
"#,
215+
r#"
216+
fn main() {
217+
write!(writer(), "{} {:b} {}"$0, y + 2, x + 1, 2);
218+
}
219+
"#,
220+
);
221+
}
222+
189223
#[test]
190224
fn single_arg() {
191225
check_assist(

0 commit comments

Comments
 (0)