Skip to content

Commit 4cc9610

Browse files
bors[bot]Veykril
andauthored
Merge #9731
9731: feat: Add `replace_char_with_string` assist r=Veykril a=Veykril Adds the counterpart for the `replace_string_with_char` assist and fixes the assist not escaping the `'` in the string `"'"` when transforming that to a char. bors r+ Co-authored-by: Lukas Wirth <[email protected]>
2 parents 0a3ac7a + 17a47a8 commit 4cc9610

File tree

3 files changed

+171
-37
lines changed

3 files changed

+171
-37
lines changed

crates/ide_assists/src/handlers/replace_string_with_char.rs

Lines changed: 153 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
use syntax::{ast, ast::IsString, AstToken, SyntaxKind::STRING};
1+
use syntax::{
2+
ast,
3+
ast::IsString,
4+
AstToken,
5+
SyntaxKind::{CHAR, STRING},
6+
TextRange, TextSize,
7+
};
28

39
use crate::{AssistContext, AssistId, AssistKind, Assists};
410

511
// Assist: replace_string_with_char
612
//
7-
// Replace string with char.
13+
// Replace string literal with char literal.
814
//
915
// ```
1016
// fn main() {
@@ -33,31 +39,56 @@ pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext) -
3339
target,
3440
|edit| {
3541
let (left, right) = quote_offets.quotes;
36-
edit.replace(left, String::from('\''));
37-
edit.replace(right, String::from('\''));
42+
edit.replace(left, '\'');
43+
edit.replace(right, '\'');
44+
if value == "'" {
45+
edit.insert(left.end(), '\\');
46+
}
47+
},
48+
)
49+
}
50+
51+
// Assist: replace_char_with_string
52+
//
53+
// Replace a char literal with a string literal.
54+
//
55+
// ```
56+
// fn main() {
57+
// find('{$0');
58+
// }
59+
// ```
60+
// ->
61+
// ```
62+
// fn main() {
63+
// find("{");
64+
// }
65+
// ```
66+
pub(crate) fn replace_char_with_string(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
67+
let token = ctx.find_token_syntax_at_offset(CHAR)?;
68+
let target = token.text_range();
69+
70+
acc.add(
71+
AssistId("replace_char_with_string", AssistKind::RefactorRewrite),
72+
"Replace char with string",
73+
target,
74+
|edit| {
75+
if token.text() == "'\"'" {
76+
edit.replace(token.text_range(), r#""\"""#);
77+
} else {
78+
let len = TextSize::of('\'');
79+
edit.replace(TextRange::at(target.start(), len), '"');
80+
edit.replace(TextRange::at(target.end() - len, len), '"');
81+
}
3882
},
3983
)
4084
}
4185

4286
#[cfg(test)]
4387
mod tests {
44-
use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
88+
use crate::tests::{check_assist, check_assist_not_applicable};
4589

4690
use super::*;
4791

48-
#[test]
49-
fn replace_string_with_char_target() {
50-
check_assist_target(
51-
replace_string_with_char,
52-
r#"
53-
fn f() {
54-
let s = "$0c";
55-
}
56-
"#,
57-
r#""c""#,
58-
);
59-
}
60-
6192
#[test]
6293
fn replace_string_with_char_assist() {
6394
check_assist(
@@ -76,7 +107,7 @@ fn f() {
76107
}
77108

78109
#[test]
79-
fn replace_string_with_char_assist_with_emoji() {
110+
fn replace_string_with_char_assist_with_multi_byte_char() {
80111
check_assist(
81112
replace_string_with_char,
82113
r#"
@@ -93,7 +124,7 @@ fn f() {
93124
}
94125

95126
#[test]
96-
fn replace_string_with_char_assist_not_applicable() {
127+
fn replace_string_with_char_multiple_chars() {
97128
check_assist_not_applicable(
98129
replace_string_with_char,
99130
r#"
@@ -121,23 +152,6 @@ fn f() {
121152
)
122153
}
123154

124-
#[test]
125-
fn replace_string_with_char_works_func_args() {
126-
check_assist(
127-
replace_string_with_char,
128-
r#"
129-
fn f() {
130-
find($0"x");
131-
}
132-
"#,
133-
r##"
134-
fn f() {
135-
find('x');
136-
}
137-
"##,
138-
)
139-
}
140-
141155
#[test]
142156
fn replace_string_with_char_newline() {
143157
check_assist(
@@ -188,4 +202,106 @@ fn f() {
188202
"##,
189203
)
190204
}
205+
206+
#[test]
207+
fn replace_char_with_string_assist() {
208+
check_assist(
209+
replace_char_with_string,
210+
r"
211+
fn f() {
212+
let s = '$0c';
213+
}
214+
",
215+
r#"
216+
fn f() {
217+
let s = "c";
218+
}
219+
"#,
220+
)
221+
}
222+
223+
#[test]
224+
fn replace_char_with_string_assist_with_multi_byte_char() {
225+
check_assist(
226+
replace_char_with_string,
227+
r"
228+
fn f() {
229+
let s = '$0😀';
230+
}
231+
",
232+
r#"
233+
fn f() {
234+
let s = "😀";
235+
}
236+
"#,
237+
)
238+
}
239+
240+
#[test]
241+
fn replace_char_with_string_newline() {
242+
check_assist(
243+
replace_char_with_string,
244+
r"
245+
fn f() {
246+
find($0'\n');
247+
}
248+
",
249+
r#"
250+
fn f() {
251+
find("\n");
252+
}
253+
"#,
254+
)
255+
}
256+
257+
#[test]
258+
fn replace_char_with_string_unicode_escape() {
259+
check_assist(
260+
replace_char_with_string,
261+
r"
262+
fn f() {
263+
find($0'\u{7FFF}');
264+
}
265+
",
266+
r#"
267+
fn f() {
268+
find("\u{7FFF}");
269+
}
270+
"#,
271+
)
272+
}
273+
274+
#[test]
275+
fn replace_char_with_string_quote() {
276+
check_assist(
277+
replace_char_with_string,
278+
r#"
279+
fn f() {
280+
find($0'"');
281+
}
282+
"#,
283+
r#"
284+
fn f() {
285+
find("\"");
286+
}
287+
"#,
288+
)
289+
}
290+
291+
#[test]
292+
fn replace_string_with_char_quote() {
293+
check_assist(
294+
replace_string_with_char,
295+
r#"
296+
fn f() {
297+
find($0"'");
298+
}
299+
"#,
300+
r#"
301+
fn f() {
302+
find('\'');
303+
}
304+
"#,
305+
)
306+
}
191307
}

crates/ide_assists/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ mod handlers {
194194
add_missing_impl_members::add_missing_default_members,
195195
//
196196
replace_string_with_char::replace_string_with_char,
197+
replace_string_with_char::replace_char_with_string,
197198
raw_string::make_raw_string,
198199
//
199200
extract_variable::extract_variable,

crates/ide_assists/src/tests/generated.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,6 +1331,23 @@ impl Foo for Bar {
13311331
)
13321332
}
13331333

1334+
#[test]
1335+
fn doctest_replace_char_with_string() {
1336+
check_doc_test(
1337+
"replace_char_with_string",
1338+
r#####"
1339+
fn main() {
1340+
find('{$0');
1341+
}
1342+
"#####,
1343+
r#####"
1344+
fn main() {
1345+
find("{");
1346+
}
1347+
"#####,
1348+
)
1349+
}
1350+
13341351
#[test]
13351352
fn doctest_replace_derive_with_manual_impl() {
13361353
check_doc_test(

0 commit comments

Comments
 (0)