aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeobert Quach <[email protected]>2019-09-15 18:51:34 +0100
committerGeobert Quach <[email protected]>2019-09-19 22:12:28 +0100
commitb6d55290a1e416e68bb258bb1e19861692476bd2 (patch)
tree42b7241a3792a586ffffeded74e53924b5fad98d
parent58dc3b16496cbcce14101605aa1214e263b91c87 (diff)
feat(assists): raw string <-> usual string manipulation
Fixes #1730
-rw-r--r--crates/ra_assists/src/lib.rs5
-rw-r--r--crates/ra_assists/src/raw_string.rs326
-rw-r--r--docs/user/features.md56
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;
96mod merge_match_arms; 96mod merge_match_arms;
97mod introduce_variable; 97mod introduce_variable;
98mod inline_local_variable; 98mod inline_local_variable;
99mod raw_string;
99mod replace_if_let_with_match; 100mod replace_if_let_with_match;
100mod split_import; 101mod split_import;
101mod remove_dbg; 102mod 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 @@
1use hir::db::HirDatabase;
2use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit};
3
4use crate::{Assist, AssistCtx, AssistId};
5
6pub(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
19pub(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
54pub(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
68pub(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)]
92mod 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>() {}
445fn foo<T, F>() where T: u32, F: FnOnce(T) -> T {} 445fn foo<T, F>() where T: u32, F: FnOnce(T) -> T {}
446``` 446```
447 447
448- Make raw string
449
450```rust
451// before:
452fn f() {
453 let s = <|>"abcd";
454}
455
456// after:
457fn f() {
458 let s = <|>r"abcd";
459}
460```
461
462- Make usual string
463
464```rust
465// before:
466fn f() {
467 let s = <|>r#"abcd"#;
468}
469
470// after:
471fn f() {
472 let s = <|>"abcd";
473}
474```
475
476- Add hash
477
478```rust
479// before:
480fn f() {
481 let s = <|>r"abcd";
482}
483
484// after:
485fn f() {
486 let s = <|>r#"abcd"#;
487}
488```
489
490- Remove hash
491
492```rust
493// before:
494fn f() {
495 let s = <|>r#"abcd"#;
496}
497
498// after:
499fn f() {
500 let s = <|>r"abcd";
501}
502```
503
448### Magic Completions 504### Magic Completions
449 505
450In addition to usual reference completion, rust-analyzer provides some ✨magic✨ 506In addition to usual reference completion, rust-analyzer provides some ✨magic✨