diff options
author | Geobert Quach <[email protected]> | 2019-09-15 18:51:34 +0100 |
---|---|---|
committer | Geobert Quach <[email protected]> | 2019-09-19 22:12:28 +0100 |
commit | b6d55290a1e416e68bb258bb1e19861692476bd2 (patch) | |
tree | 42b7241a3792a586ffffeded74e53924b5fad98d | |
parent | 58dc3b16496cbcce14101605aa1214e263b91c87 (diff) |
feat(assists): raw string <-> usual string manipulation
Fixes #1730
-rw-r--r-- | crates/ra_assists/src/lib.rs | 5 | ||||
-rw-r--r-- | crates/ra_assists/src/raw_string.rs | 326 | ||||
-rw-r--r-- | docs/user/features.md | 56 |
3 files changed, 387 insertions, 0 deletions
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 66cf32524..756acf415 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -96,6 +96,7 @@ mod fill_match_arms; | |||
96 | mod merge_match_arms; | 96 | mod merge_match_arms; |
97 | mod introduce_variable; | 97 | mod introduce_variable; |
98 | mod inline_local_variable; | 98 | mod inline_local_variable; |
99 | mod raw_string; | ||
99 | mod replace_if_let_with_match; | 100 | mod replace_if_let_with_match; |
100 | mod split_import; | 101 | mod split_import; |
101 | mod remove_dbg; | 102 | mod remove_dbg; |
@@ -125,6 +126,10 @@ fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assis | |||
125 | move_guard::move_guard_to_arm_body, | 126 | move_guard::move_guard_to_arm_body, |
126 | move_guard::move_arm_cond_to_match_guard, | 127 | move_guard::move_arm_cond_to_match_guard, |
127 | move_bounds::move_bounds_to_where_clause, | 128 | move_bounds::move_bounds_to_where_clause, |
129 | raw_string::add_hash, | ||
130 | raw_string::make_raw_string, | ||
131 | raw_string::make_usual_string, | ||
132 | raw_string::remove_hash, | ||
128 | ] | 133 | ] |
129 | } | 134 | } |
130 | 135 | ||
diff --git a/crates/ra_assists/src/raw_string.rs b/crates/ra_assists/src/raw_string.rs new file mode 100644 index 000000000..59dc8d078 --- /dev/null +++ b/crates/ra_assists/src/raw_string.rs | |||
@@ -0,0 +1,326 @@ | |||
1 | use hir::db::HirDatabase; | ||
2 | use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; | ||
3 | |||
4 | use crate::{Assist, AssistCtx, AssistId}; | ||
5 | |||
6 | pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
7 | let literal = ctx.node_at_offset::<Literal>()?; | ||
8 | if literal.token().kind() == ra_syntax::SyntaxKind::STRING { | ||
9 | ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| { | ||
10 | edit.target(literal.syntax().text_range()); | ||
11 | edit.insert(literal.syntax().text_range().start(), "r"); | ||
12 | }); | ||
13 | ctx.build() | ||
14 | } else { | ||
15 | None | ||
16 | } | ||
17 | } | ||
18 | |||
19 | pub(crate) fn make_usual_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
20 | let literal = ctx.node_at_offset::<Literal>()?; | ||
21 | if literal.token().kind() == ra_syntax::SyntaxKind::RAW_STRING { | ||
22 | ctx.add_action(AssistId("make_usual_string"), "make usual string", |edit| { | ||
23 | let text = literal.syntax().text(); | ||
24 | let usual_start_pos = text.find_char('"').unwrap(); // we have a RAW_STRING | ||
25 | let end = literal.syntax().text_range().end(); | ||
26 | dbg!(&end); | ||
27 | let mut i = 0; | ||
28 | let mut pos = 0; | ||
29 | let mut c = text.char_at(end - TextUnit::from(i)); | ||
30 | while c != Some('"') { | ||
31 | if c != None { | ||
32 | pos += 1; | ||
33 | } | ||
34 | i += 1; | ||
35 | c = text.char_at(end - TextUnit::from(i)); | ||
36 | } | ||
37 | |||
38 | edit.target(literal.syntax().text_range()); | ||
39 | edit.delete(TextRange::from_to( | ||
40 | literal.syntax().text_range().start(), | ||
41 | literal.syntax().text_range().start() + usual_start_pos, | ||
42 | )); | ||
43 | edit.delete(TextRange::from_to( | ||
44 | literal.syntax().text_range().end() - TextUnit::from(pos), | ||
45 | literal.syntax().text_range().end(), | ||
46 | )); | ||
47 | }); | ||
48 | ctx.build() | ||
49 | } else { | ||
50 | None | ||
51 | } | ||
52 | } | ||
53 | |||
54 | pub(crate) fn add_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
55 | let literal = ctx.node_at_offset::<Literal>()?; | ||
56 | if literal.token().kind() == ra_syntax::SyntaxKind::RAW_STRING { | ||
57 | ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| { | ||
58 | edit.target(literal.syntax().text_range()); | ||
59 | edit.insert(literal.syntax().text_range().start() + TextUnit::from(1), "#"); | ||
60 | edit.insert(literal.syntax().text_range().end(), "#"); | ||
61 | }); | ||
62 | ctx.build() | ||
63 | } else { | ||
64 | None | ||
65 | } | ||
66 | } | ||
67 | |||
68 | pub(crate) fn remove_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
69 | let literal = ctx.node_at_offset::<Literal>()?; | ||
70 | if literal.token().kind() == ra_syntax::SyntaxKind::RAW_STRING { | ||
71 | if !literal.syntax().text().contains_char('#') { | ||
72 | return None; | ||
73 | } | ||
74 | ctx.add_action(AssistId("remove_hash"), "remove hash from raw string", |edit| { | ||
75 | edit.target(literal.syntax().text_range()); | ||
76 | edit.delete(TextRange::from_to( | ||
77 | literal.syntax().text_range().start() + TextUnit::from(1), | ||
78 | literal.syntax().text_range().start() + TextUnit::from(2), | ||
79 | )); | ||
80 | edit.delete(TextRange::from_to( | ||
81 | literal.syntax().text_range().end() - TextUnit::from(1), | ||
82 | literal.syntax().text_range().end(), | ||
83 | )); | ||
84 | }); | ||
85 | ctx.build() | ||
86 | } else { | ||
87 | None | ||
88 | } | ||
89 | } | ||
90 | |||
91 | #[cfg(test)] | ||
92 | mod test { | ||
93 | use super::*; | ||
94 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | ||
95 | |||
96 | #[test] | ||
97 | fn make_raw_string_target() { | ||
98 | check_assist_target( | ||
99 | make_raw_string, | ||
100 | r#" | ||
101 | fn f() { | ||
102 | let s = <|>"random string"; | ||
103 | } | ||
104 | "#, | ||
105 | r#""random string""#, | ||
106 | ); | ||
107 | } | ||
108 | |||
109 | #[test] | ||
110 | fn make_raw_string_works() { | ||
111 | check_assist( | ||
112 | make_raw_string, | ||
113 | r#" | ||
114 | fn f() { | ||
115 | let s = <|>"random string"; | ||
116 | } | ||
117 | "#, | ||
118 | r#" | ||
119 | fn f() { | ||
120 | let s = <|>r"random string"; | ||
121 | } | ||
122 | "#, | ||
123 | ) | ||
124 | } | ||
125 | |||
126 | #[test] | ||
127 | fn make_raw_string_not_works() { | ||
128 | check_assist_not_applicable( | ||
129 | make_raw_string, | ||
130 | r#" | ||
131 | fn f() { | ||
132 | let s = <|>r"random string"; | ||
133 | } | ||
134 | "#, | ||
135 | ); | ||
136 | } | ||
137 | |||
138 | #[test] | ||
139 | fn add_hash_target() { | ||
140 | check_assist_target( | ||
141 | add_hash, | ||
142 | r#" | ||
143 | fn f() { | ||
144 | let s = <|>r"random string"; | ||
145 | } | ||
146 | "#, | ||
147 | r#"r"random string""#, | ||
148 | ); | ||
149 | } | ||
150 | |||
151 | #[test] | ||
152 | fn add_hash_works() { | ||
153 | check_assist( | ||
154 | add_hash, | ||
155 | r#" | ||
156 | fn f() { | ||
157 | let s = <|>r"random string"; | ||
158 | } | ||
159 | "#, | ||
160 | r##" | ||
161 | fn f() { | ||
162 | let s = <|>r#"random string"#; | ||
163 | } | ||
164 | "##, | ||
165 | ) | ||
166 | } | ||
167 | |||
168 | #[test] | ||
169 | fn add_more_hash_works() { | ||
170 | check_assist( | ||
171 | add_hash, | ||
172 | r##" | ||
173 | fn f() { | ||
174 | let s = <|>r#"random string"#; | ||
175 | } | ||
176 | "##, | ||
177 | r###" | ||
178 | fn f() { | ||
179 | let s = <|>r##"random string"##; | ||
180 | } | ||
181 | "###, | ||
182 | ) | ||
183 | } | ||
184 | |||
185 | #[test] | ||
186 | fn add_hash_not_works() { | ||
187 | check_assist_not_applicable( | ||
188 | add_hash, | ||
189 | r#" | ||
190 | fn f() { | ||
191 | let s = <|>"random string"; | ||
192 | } | ||
193 | "#, | ||
194 | ); | ||
195 | } | ||
196 | |||
197 | #[test] | ||
198 | fn remove_hash_target() { | ||
199 | check_assist_target( | ||
200 | remove_hash, | ||
201 | r##" | ||
202 | fn f() { | ||
203 | let s = <|>r#"random string"#; | ||
204 | } | ||
205 | "##, | ||
206 | r##"r#"random string"#"##, | ||
207 | ); | ||
208 | } | ||
209 | |||
210 | #[test] | ||
211 | fn remove_hash_works() { | ||
212 | check_assist( | ||
213 | remove_hash, | ||
214 | r##" | ||
215 | fn f() { | ||
216 | let s = <|>r#"random string"#; | ||
217 | } | ||
218 | "##, | ||
219 | r#" | ||
220 | fn f() { | ||
221 | let s = <|>r"random string"; | ||
222 | } | ||
223 | "#, | ||
224 | ) | ||
225 | } | ||
226 | |||
227 | #[test] | ||
228 | fn remove_more_hash_works() { | ||
229 | check_assist( | ||
230 | remove_hash, | ||
231 | r###" | ||
232 | fn f() { | ||
233 | let s = <|>r##"random string"##; | ||
234 | } | ||
235 | "###, | ||
236 | r##" | ||
237 | fn f() { | ||
238 | let s = <|>r#"random string"#; | ||
239 | } | ||
240 | "##, | ||
241 | ) | ||
242 | } | ||
243 | |||
244 | #[test] | ||
245 | fn remove_hash_not_works() { | ||
246 | check_assist_not_applicable( | ||
247 | remove_hash, | ||
248 | r#" | ||
249 | fn f() { | ||
250 | let s = <|>"random string"; | ||
251 | } | ||
252 | "#, | ||
253 | ); | ||
254 | } | ||
255 | |||
256 | #[test] | ||
257 | fn remove_hash_no_hash_not_works() { | ||
258 | check_assist_not_applicable( | ||
259 | remove_hash, | ||
260 | r#" | ||
261 | fn f() { | ||
262 | let s = <|>r"random string"; | ||
263 | } | ||
264 | "#, | ||
265 | ); | ||
266 | } | ||
267 | |||
268 | #[test] | ||
269 | fn make_usual_string_target() { | ||
270 | check_assist_target( | ||
271 | make_usual_string, | ||
272 | r##" | ||
273 | fn f() { | ||
274 | let s = <|>r#"random string"#; | ||
275 | } | ||
276 | "##, | ||
277 | r##"r#"random string"#"##, | ||
278 | ); | ||
279 | } | ||
280 | |||
281 | #[test] | ||
282 | fn make_usual_string_works() { | ||
283 | check_assist( | ||
284 | make_usual_string, | ||
285 | r##" | ||
286 | fn f() { | ||
287 | let s = <|>r#"random string"#; | ||
288 | } | ||
289 | "##, | ||
290 | r#" | ||
291 | fn f() { | ||
292 | let s = <|>"random string"; | ||
293 | } | ||
294 | "#, | ||
295 | ) | ||
296 | } | ||
297 | |||
298 | #[test] | ||
299 | fn make_usual_string_more_hash_works() { | ||
300 | check_assist( | ||
301 | make_usual_string, | ||
302 | r###" | ||
303 | fn f() { | ||
304 | let s = <|>r##"random string"##; | ||
305 | } | ||
306 | "###, | ||
307 | r##" | ||
308 | fn f() { | ||
309 | let s = <|>"random string"; | ||
310 | } | ||
311 | "##, | ||
312 | ) | ||
313 | } | ||
314 | |||
315 | #[test] | ||
316 | fn make_usual_string_not_works() { | ||
317 | check_assist_not_applicable( | ||
318 | make_usual_string, | ||
319 | r#" | ||
320 | fn f() { | ||
321 | let s = <|>"random string"; | ||
322 | } | ||
323 | "#, | ||
324 | ); | ||
325 | } | ||
326 | } | ||
diff --git a/docs/user/features.md b/docs/user/features.md index 1034a5117..93e565315 100644 --- a/docs/user/features.md +++ b/docs/user/features.md | |||
@@ -445,6 +445,62 @@ fn foo<T: u32, F: FnOnce(T) -> T>() {} | |||
445 | fn foo<T, F>() where T: u32, F: FnOnce(T) -> T {} | 445 | fn foo<T, F>() where T: u32, F: FnOnce(T) -> T {} |
446 | ``` | 446 | ``` |
447 | 447 | ||
448 | - Make raw string | ||
449 | |||
450 | ```rust | ||
451 | // before: | ||
452 | fn f() { | ||
453 | let s = <|>"abcd"; | ||
454 | } | ||
455 | |||
456 | // after: | ||
457 | fn f() { | ||
458 | let s = <|>r"abcd"; | ||
459 | } | ||
460 | ``` | ||
461 | |||
462 | - Make usual string | ||
463 | |||
464 | ```rust | ||
465 | // before: | ||
466 | fn f() { | ||
467 | let s = <|>r#"abcd"#; | ||
468 | } | ||
469 | |||
470 | // after: | ||
471 | fn f() { | ||
472 | let s = <|>"abcd"; | ||
473 | } | ||
474 | ``` | ||
475 | |||
476 | - Add hash | ||
477 | |||
478 | ```rust | ||
479 | // before: | ||
480 | fn f() { | ||
481 | let s = <|>r"abcd"; | ||
482 | } | ||
483 | |||
484 | // after: | ||
485 | fn f() { | ||
486 | let s = <|>r#"abcd"#; | ||
487 | } | ||
488 | ``` | ||
489 | |||
490 | - Remove hash | ||
491 | |||
492 | ```rust | ||
493 | // before: | ||
494 | fn f() { | ||
495 | let s = <|>r#"abcd"#; | ||
496 | } | ||
497 | |||
498 | // after: | ||
499 | fn f() { | ||
500 | let s = <|>r"abcd"; | ||
501 | } | ||
502 | ``` | ||
503 | |||
448 | ### Magic Completions | 504 | ### Magic Completions |
449 | 505 | ||
450 | In addition to usual reference completion, rust-analyzer provides some ✨magic✨ | 506 | In addition to usual reference completion, rust-analyzer provides some ✨magic✨ |