aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-09-20 11:40:15 +0100
committerGitHub <[email protected]>2019-09-20 11:40:15 +0100
commitb19da133eec13ac8943b708d17410e3a8a6b6193 (patch)
tree2e1b540b6914c4b7e11b7b51d878a4d45aea859f /crates
parent4101c15ddbae860b86cd2ed17b09b7526ef17de8 (diff)
parentce4d84365632ea379caa6c79580b1e458dde39f7 (diff)
Merge #1850
1850: feat(assists): raw string <-> usual string manipulation r=matklad a=Geobert Fixes #1730 Co-authored-by: Geobert Quach <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/lib.rs5
-rw-r--r--crates/ra_assists/src/raw_string.rs370
2 files changed, 375 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..e00267060
--- /dev/null
+++ b/crates/ra_assists/src/raw_string.rs
@@ -0,0 +1,370 @@
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 return None;
10 }
11 ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| {
12 edit.target(literal.syntax().text_range());
13 edit.insert(literal.syntax().text_range().start(), "r");
14 });
15 ctx.build()
16}
17
18fn find_usual_string_range(s: &str) -> Option<TextRange> {
19 Some(TextRange::from_to(
20 TextUnit::from(s.find('"')? as u32),
21 TextUnit::from(s.rfind('"')? as u32),
22 ))
23}
24
25pub(crate) fn make_usual_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
26 let literal = ctx.node_at_offset::<Literal>()?;
27 if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING {
28 return None;
29 }
30 let token = literal.token();
31 let text = token.text().as_str();
32 let usual_string_range = find_usual_string_range(text)?;
33 ctx.add_action(AssistId("make_usual_string"), "make usual string", |edit| {
34 edit.target(literal.syntax().text_range());
35 // parse inside string to escape `"`
36 let start_of_inside = usual_string_range.start().to_usize() + 1;
37 let end_of_inside = usual_string_range.end().to_usize();
38 let inside_str = &text[start_of_inside..end_of_inside];
39 let escaped = inside_str.escape_default().to_string();
40 edit.replace(literal.syntax().text_range(), format!("\"{}\"", escaped));
41 });
42 ctx.build()
43}
44
45pub(crate) fn add_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
46 let literal = ctx.node_at_offset::<Literal>()?;
47 if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING {
48 return None;
49 }
50 ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| {
51 edit.target(literal.syntax().text_range());
52 edit.insert(literal.syntax().text_range().start() + TextUnit::of_char('r'), "#");
53 edit.insert(literal.syntax().text_range().end(), "#");
54 });
55 ctx.build()
56}
57
58pub(crate) fn remove_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
59 let literal = ctx.node_at_offset::<Literal>()?;
60 if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING {
61 return None;
62 }
63 let token = literal.token();
64 let text = token.text().as_str();
65 if text.starts_with("r\"") {
66 // no hash to remove
67 return None;
68 }
69 ctx.add_action(AssistId("remove_hash"), "remove hash from raw string", |edit| {
70 edit.target(literal.syntax().text_range());
71 let result = &text[2..text.len() - 1];
72 let result = if result.starts_with("\"") {
73 // no more hash, escape
74 let internal_str = &result[1..result.len() - 1];
75 format!("\"{}\"", internal_str.escape_default().to_string())
76 } else {
77 result.to_owned()
78 };
79 edit.replace(literal.syntax().text_range(), format!("r{}", result));
80 });
81 ctx.build()
82}
83
84#[cfg(test)]
85mod test {
86 use super::*;
87 use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target};
88
89 #[test]
90 fn make_raw_string_target() {
91 check_assist_target(
92 make_raw_string,
93 r#"
94 fn f() {
95 let s = <|>"random string";
96 }
97 "#,
98 r#""random string""#,
99 );
100 }
101
102 #[test]
103 fn make_raw_string_works() {
104 check_assist(
105 make_raw_string,
106 r#"
107 fn f() {
108 let s = <|>"random string";
109 }
110 "#,
111 r#"
112 fn f() {
113 let s = <|>r"random string";
114 }
115 "#,
116 )
117 }
118
119 #[test]
120 fn make_raw_string_with_escaped_works() {
121 check_assist(
122 make_raw_string,
123 r#"
124 fn f() {
125 let s = <|>"random\nstring";
126 }
127 "#,
128 r#"
129 fn f() {
130 let s = <|>r"random\nstring";
131 }
132 "#,
133 )
134 }
135
136 #[test]
137 fn make_raw_string_not_works() {
138 check_assist_not_applicable(
139 make_raw_string,
140 r#"
141 fn f() {
142 let s = <|>r"random string";
143 }
144 "#,
145 );
146 }
147
148 #[test]
149 fn add_hash_target() {
150 check_assist_target(
151 add_hash,
152 r#"
153 fn f() {
154 let s = <|>r"random string";
155 }
156 "#,
157 r#"r"random string""#,
158 );
159 }
160
161 #[test]
162 fn add_hash_works() {
163 check_assist(
164 add_hash,
165 r#"
166 fn f() {
167 let s = <|>r"random string";
168 }
169 "#,
170 r##"
171 fn f() {
172 let s = <|>r#"random string"#;
173 }
174 "##,
175 )
176 }
177
178 #[test]
179 fn add_more_hash_works() {
180 check_assist(
181 add_hash,
182 r##"
183 fn f() {
184 let s = <|>r#"random"string"#;
185 }
186 "##,
187 r###"
188 fn f() {
189 let s = <|>r##"random"string"##;
190 }
191 "###,
192 )
193 }
194
195 #[test]
196 fn add_hash_not_works() {
197 check_assist_not_applicable(
198 add_hash,
199 r#"
200 fn f() {
201 let s = <|>"random string";
202 }
203 "#,
204 );
205 }
206
207 #[test]
208 fn remove_hash_target() {
209 check_assist_target(
210 remove_hash,
211 r##"
212 fn f() {
213 let s = <|>r#"random string"#;
214 }
215 "##,
216 r##"r#"random string"#"##,
217 );
218 }
219
220 #[test]
221 fn remove_hash_works() {
222 check_assist(
223 remove_hash,
224 r##"
225 fn f() {
226 let s = <|>r#"random string"#;
227 }
228 "##,
229 r#"
230 fn f() {
231 let s = <|>r"random string";
232 }
233 "#,
234 )
235 }
236
237 #[test]
238 fn remove_hash_with_quote_works() {
239 check_assist(
240 remove_hash,
241 r##"
242 fn f() {
243 let s = <|>r#"random"str"ing"#;
244 }
245 "##,
246 r#"
247 fn f() {
248 let s = <|>r"random\"str\"ing";
249 }
250 "#,
251 )
252 }
253
254 #[test]
255 fn remove_more_hash_works() {
256 check_assist(
257 remove_hash,
258 r###"
259 fn f() {
260 let s = <|>r##"random string"##;
261 }
262 "###,
263 r##"
264 fn f() {
265 let s = <|>r#"random string"#;
266 }
267 "##,
268 )
269 }
270
271 #[test]
272 fn remove_hash_not_works() {
273 check_assist_not_applicable(
274 remove_hash,
275 r#"
276 fn f() {
277 let s = <|>"random string";
278 }
279 "#,
280 );
281 }
282
283 #[test]
284 fn remove_hash_no_hash_not_works() {
285 check_assist_not_applicable(
286 remove_hash,
287 r#"
288 fn f() {
289 let s = <|>r"random string";
290 }
291 "#,
292 );
293 }
294
295 #[test]
296 fn make_usual_string_target() {
297 check_assist_target(
298 make_usual_string,
299 r##"
300 fn f() {
301 let s = <|>r#"random string"#;
302 }
303 "##,
304 r##"r#"random string"#"##,
305 );
306 }
307
308 #[test]
309 fn make_usual_string_works() {
310 check_assist(
311 make_usual_string,
312 r##"
313 fn f() {
314 let s = <|>r#"random string"#;
315 }
316 "##,
317 r#"
318 fn f() {
319 let s = <|>"random string";
320 }
321 "#,
322 )
323 }
324
325 #[test]
326 fn make_usual_string_with_quote_works() {
327 check_assist(
328 make_usual_string,
329 r##"
330 fn f() {
331 let s = <|>r#"random"str"ing"#;
332 }
333 "##,
334 r#"
335 fn f() {
336 let s = <|>"random\"str\"ing";
337 }
338 "#,
339 )
340 }
341
342 #[test]
343 fn make_usual_string_more_hash_works() {
344 check_assist(
345 make_usual_string,
346 r###"
347 fn f() {
348 let s = <|>r##"random string"##;
349 }
350 "###,
351 r##"
352 fn f() {
353 let s = <|>"random string";
354 }
355 "##,
356 )
357 }
358
359 #[test]
360 fn make_usual_string_not_works() {
361 check_assist_not_applicable(
362 make_usual_string,
363 r#"
364 fn f() {
365 let s = <|>"random string";
366 }
367 "#,
368 );
369 }
370}