diff options
| author | Chayim Refael Friedman <chayimfr@gmail.com> | 2025-08-10 07:10:10 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-10 07:10:10 +0000 |
| commit | e52666380f6f03fb1211138171e0ef626ceb468d (patch) | |
| tree | f5340385844f95d5e0987a967b322fd166010091 | |
| parent | 949c649c37a2b3a6112786ec1b83b9f55705a715 (diff) | |
| parent | 8c0f4b40803a6d0c6ed6525026217c8d2532d205 (diff) | |
| download | rust-e52666380f6f03fb1211138171e0ef626ceb468d.tar.gz rust-e52666380f6f03fb1211138171e0ef626ceb468d.zip | |
Merge pull request #20418 from A4-Tacks/fix-extract-expr-from-fmtstr-on-write
Fix extract_expressions_from_format_string on write!
| -rw-r--r-- | src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs | 46 |
1 files changed, 40 insertions, 6 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs index cdc0e967101..e3c7ea1b093 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs @@ -7,8 +7,8 @@ use itertools::Itertools; use syntax::{ AstNode, AstToken, NodeOrToken, SyntaxKind::WHITESPACE, - T, - ast::{self, make, syntax_factory::SyntaxFactory}, + SyntaxToken, T, + ast::{self, TokenTree, make, syntax_factory::SyntaxFactory}, }; // Assist: extract_expressions_from_format_string @@ -58,10 +58,11 @@ pub(crate) fn extract_expressions_from_format_string( tt.syntax().text_range(), |edit| { // Extract existing arguments in macro - let tokens = tt.token_trees_and_tokens().collect_vec(); + let mut raw_tokens = tt.token_trees_and_tokens().skip(1).collect_vec(); + let format_string_index = format_str_index(&raw_tokens, &fmt_string); + let tokens = raw_tokens.split_off(format_string_index); let existing_args = if let [ - _opening_bracket, NodeOrToken::Token(_format_string), _args_start_comma, tokens @ .., @@ -90,9 +91,11 @@ pub(crate) fn extract_expressions_from_format_string( // Start building the new args let mut existing_args = existing_args.into_iter(); - let mut new_tt_bits = vec![NodeOrToken::Token(make::tokens::literal(&new_fmt))]; + let mut new_tt_bits = raw_tokens; let mut placeholder_indexes = vec![]; + new_tt_bits.push(NodeOrToken::Token(make::tokens::literal(&new_fmt))); + for arg in extracted_args { if matches!(arg, Arg::Expr(_) | Arg::Placeholder) { // insert ", " before each arg @@ -150,7 +153,9 @@ pub(crate) fn extract_expressions_from_format_string( } // Add the final tabstop after the format literal - if let Some(NodeOrToken::Token(literal)) = new_tt.token_trees_and_tokens().nth(1) { + if let Some(NodeOrToken::Token(literal)) = + new_tt.token_trees_and_tokens().nth(1 + format_string_index) + { let annotation = edit.make_tabstop_after(cap); editor.add_annotation(literal, annotation); } @@ -163,6 +168,17 @@ pub(crate) fn extract_expressions_from_format_string( Some(()) } +fn format_str_index( + raw_tokens: &[NodeOrToken<TokenTree, SyntaxToken>], + fmt_string: &ast::String, +) -> usize { + let fmt_string = fmt_string.syntax(); + raw_tokens + .iter() + .position(|tt| tt.as_token().is_some_and(|tt| tt == fmt_string)) + .unwrap_or_default() +} + #[cfg(test)] mod tests { use super::*; @@ -187,6 +203,24 @@ fn main() { } #[test] + fn multiple_middle_arg_on_write() { + check_assist( + extract_expressions_from_format_string, + r#" +//- minicore: write +fn main() { + write!(writer(), "{} {x + 1:b} {}$0", y + 2, 2); +} +"#, + r#" +fn main() { + write!(writer(), "{} {:b} {}"$0, y + 2, x + 1, 2); +} +"#, + ); + } + + #[test] fn single_arg() { check_assist( extract_expressions_from_format_string, |
