]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_string_with_char.rs
Rollup merge of #101420 - kraktus:doc_hir_local, r=cjgillot
[rust.git] / src / tools / rust-analyzer / crates / ide-assists / src / handlers / replace_string_with_char.rs
1 use syntax::{
2     ast,
3     ast::IsString,
4     AstToken,
5     SyntaxKind::{CHAR, STRING},
6     TextRange, TextSize,
7 };
8
9 use crate::{AssistContext, AssistId, AssistKind, Assists};
10
11 // Assist: replace_string_with_char
12 //
13 // Replace string literal with char literal.
14 //
15 // ```
16 // fn main() {
17 //     find("{$0");
18 // }
19 // ```
20 // ->
21 // ```
22 // fn main() {
23 //     find('{');
24 // }
25 // ```
26 pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
27     let token = ctx.find_token_syntax_at_offset(STRING).and_then(ast::String::cast)?;
28     let value = token.value()?;
29     let target = token.syntax().text_range();
30
31     if value.chars().take(2).count() != 1 {
32         return None;
33     }
34     let quote_offets = token.quote_offsets()?;
35
36     acc.add(
37         AssistId("replace_string_with_char", AssistKind::RefactorRewrite),
38         "Replace string with char",
39         target,
40         |edit| {
41             let (left, right) = quote_offets.quotes;
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             }
82         },
83     )
84 }
85
86 #[cfg(test)]
87 mod tests {
88     use crate::tests::{check_assist, check_assist_not_applicable};
89
90     use super::*;
91
92     #[test]
93     fn replace_string_with_char_assist() {
94         check_assist(
95             replace_string_with_char,
96             r#"
97 fn f() {
98     let s = "$0c";
99 }
100 "#,
101             r##"
102 fn f() {
103     let s = 'c';
104 }
105 "##,
106         )
107     }
108
109     #[test]
110     fn replace_string_with_char_assist_with_multi_byte_char() {
111         check_assist(
112             replace_string_with_char,
113             r#"
114 fn f() {
115     let s = "$0😀";
116 }
117 "#,
118             r##"
119 fn f() {
120     let s = '😀';
121 }
122 "##,
123         )
124     }
125
126     #[test]
127     fn replace_string_with_char_multiple_chars() {
128         check_assist_not_applicable(
129             replace_string_with_char,
130             r#"
131 fn f() {
132     let s = "$0test";
133 }
134 "#,
135         )
136     }
137
138     #[test]
139     fn replace_string_with_char_works_inside_macros() {
140         check_assist(
141             replace_string_with_char,
142             r#"
143 fn f() {
144     format!($0"x", 92)
145 }
146 "#,
147             r##"
148 fn f() {
149     format!('x', 92)
150 }
151 "##,
152         )
153     }
154
155     #[test]
156     fn replace_string_with_char_newline() {
157         check_assist(
158             replace_string_with_char,
159             r#"
160 fn f() {
161     find($0"\n");
162 }
163 "#,
164             r##"
165 fn f() {
166     find('\n');
167 }
168 "##,
169         )
170     }
171
172     #[test]
173     fn replace_string_with_char_unicode_escape() {
174         check_assist(
175             replace_string_with_char,
176             r#"
177 fn f() {
178     find($0"\u{7FFF}");
179 }
180 "#,
181             r##"
182 fn f() {
183     find('\u{7FFF}');
184 }
185 "##,
186         )
187     }
188
189     #[test]
190     fn replace_raw_string_with_char() {
191         check_assist(
192             replace_string_with_char,
193             r##"
194 fn f() {
195     $0r#"X"#
196 }
197 "##,
198             r##"
199 fn f() {
200     'X'
201 }
202 "##,
203         )
204     }
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     }
307 }