diff options
-rw-r--r-- | crates/ra_assists/src/raw_string.rs | 95 |
1 files changed, 90 insertions, 5 deletions
diff --git a/crates/ra_assists/src/raw_string.rs b/crates/ra_assists/src/raw_string.rs index 59dc8d078..10ed93173 100644 --- a/crates/ra_assists/src/raw_string.rs +++ b/crates/ra_assists/src/raw_string.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
2 | use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; | 2 | use ra_syntax::{ast::AstNode, ast::Literal, SyntaxText, TextRange, TextUnit}; |
3 | 3 | ||
4 | use crate::{Assist, AssistCtx, AssistId}; | 4 | use crate::{assist_ctx::AssistBuilder, Assist, AssistCtx, AssistId}; |
5 | 5 | ||
6 | pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 6 | pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
7 | let literal = ctx.node_at_offset::<Literal>()?; | 7 | let literal = ctx.node_at_offset::<Literal>()?; |
@@ -23,7 +23,6 @@ pub(crate) fn make_usual_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option< | |||
23 | let text = literal.syntax().text(); | 23 | let text = literal.syntax().text(); |
24 | let usual_start_pos = text.find_char('"').unwrap(); // we have a RAW_STRING | 24 | let usual_start_pos = text.find_char('"').unwrap(); // we have a RAW_STRING |
25 | let end = literal.syntax().text_range().end(); | 25 | let end = literal.syntax().text_range().end(); |
26 | dbg!(&end); | ||
27 | let mut i = 0; | 26 | let mut i = 0; |
28 | let mut pos = 0; | 27 | let mut pos = 0; |
29 | let mut c = text.char_at(end - TextUnit::from(i)); | 28 | let mut c = text.char_at(end - TextUnit::from(i)); |
@@ -44,6 +43,15 @@ pub(crate) fn make_usual_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option< | |||
44 | literal.syntax().text_range().end() - TextUnit::from(pos), | 43 | literal.syntax().text_range().end() - TextUnit::from(pos), |
45 | literal.syntax().text_range().end(), | 44 | literal.syntax().text_range().end(), |
46 | )); | 45 | )); |
46 | // parse inside string to escape `"` | ||
47 | let start_of_inside = usual_start_pos + TextUnit::from(1); | ||
48 | let inside_str = | ||
49 | text.slice(TextRange::from_to(start_of_inside, text.len() - TextUnit::from(2))); | ||
50 | escape_quote( | ||
51 | edit, | ||
52 | &inside_str, | ||
53 | literal.syntax().text_range().start() + start_of_inside, | ||
54 | ); | ||
47 | }); | 55 | }); |
48 | ctx.build() | 56 | ctx.build() |
49 | } else { | 57 | } else { |
@@ -65,6 +73,21 @@ pub(crate) fn add_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | |||
65 | } | 73 | } |
66 | } | 74 | } |
67 | 75 | ||
76 | fn escape_quote(edit: &mut AssistBuilder, inside_str: &SyntaxText, offset: TextUnit) { | ||
77 | let mut start = TextUnit::from(0); | ||
78 | inside_str.for_each_chunk(|chunk| { | ||
79 | let end = start + TextUnit::of_str(chunk); | ||
80 | let mut i = 0; | ||
81 | for c in chunk.to_string().chars() { | ||
82 | if c == '"' { | ||
83 | edit.insert(offset + start + TextUnit::from(i), "\\"); | ||
84 | } | ||
85 | i += 1; | ||
86 | } | ||
87 | start = end; | ||
88 | }); | ||
89 | } | ||
90 | |||
68 | pub(crate) fn remove_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 91 | pub(crate) fn remove_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
69 | let literal = ctx.node_at_offset::<Literal>()?; | 92 | let literal = ctx.node_at_offset::<Literal>()?; |
70 | if literal.token().kind() == ra_syntax::SyntaxKind::RAW_STRING { | 93 | if literal.token().kind() == ra_syntax::SyntaxKind::RAW_STRING { |
@@ -81,6 +104,17 @@ pub(crate) fn remove_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist | |||
81 | literal.syntax().text_range().end() - TextUnit::from(1), | 104 | literal.syntax().text_range().end() - TextUnit::from(1), |
82 | literal.syntax().text_range().end(), | 105 | literal.syntax().text_range().end(), |
83 | )); | 106 | )); |
107 | let text = literal.syntax().text(); | ||
108 | if text.char_at(TextUnit::from(2)) == Some('"') { | ||
109 | // no more hash after assist, need to escape any `"` in the string | ||
110 | let inside_str = text | ||
111 | .slice(TextRange::from_to(TextUnit::from(3), text.len() - TextUnit::from(2))); | ||
112 | escape_quote( | ||
113 | edit, | ||
114 | &inside_str, | ||
115 | literal.syntax().text_range().start() + TextUnit::from(3), | ||
116 | ); | ||
117 | } | ||
84 | }); | 118 | }); |
85 | ctx.build() | 119 | ctx.build() |
86 | } else { | 120 | } else { |
@@ -124,6 +158,23 @@ mod test { | |||
124 | } | 158 | } |
125 | 159 | ||
126 | #[test] | 160 | #[test] |
161 | fn make_raw_string_with_escaped_works() { | ||
162 | check_assist( | ||
163 | make_raw_string, | ||
164 | r#" | ||
165 | fn f() { | ||
166 | let s = <|>"random\nstring"; | ||
167 | } | ||
168 | "#, | ||
169 | r#" | ||
170 | fn f() { | ||
171 | let s = <|>r"random\nstring"; | ||
172 | } | ||
173 | "#, | ||
174 | ) | ||
175 | } | ||
176 | |||
177 | #[test] | ||
127 | fn make_raw_string_not_works() { | 178 | fn make_raw_string_not_works() { |
128 | check_assist_not_applicable( | 179 | check_assist_not_applicable( |
129 | make_raw_string, | 180 | make_raw_string, |
@@ -171,12 +222,12 @@ mod test { | |||
171 | add_hash, | 222 | add_hash, |
172 | r##" | 223 | r##" |
173 | fn f() { | 224 | fn f() { |
174 | let s = <|>r#"random string"#; | 225 | let s = <|>r#"random"string"#; |
175 | } | 226 | } |
176 | "##, | 227 | "##, |
177 | r###" | 228 | r###" |
178 | fn f() { | 229 | fn f() { |
179 | let s = <|>r##"random string"##; | 230 | let s = <|>r##"random"string"##; |
180 | } | 231 | } |
181 | "###, | 232 | "###, |
182 | ) | 233 | ) |
@@ -225,6 +276,23 @@ mod test { | |||
225 | } | 276 | } |
226 | 277 | ||
227 | #[test] | 278 | #[test] |
279 | fn remove_hash_with_quote_works() { | ||
280 | check_assist( | ||
281 | remove_hash, | ||
282 | r##" | ||
283 | fn f() { | ||
284 | let s = <|>r#"random"str"ing"#; | ||
285 | } | ||
286 | "##, | ||
287 | r#" | ||
288 | fn f() { | ||
289 | let s = <|>r"random\"str\"ing"; | ||
290 | } | ||
291 | "#, | ||
292 | ) | ||
293 | } | ||
294 | |||
295 | #[test] | ||
228 | fn remove_more_hash_works() { | 296 | fn remove_more_hash_works() { |
229 | check_assist( | 297 | check_assist( |
230 | remove_hash, | 298 | remove_hash, |
@@ -296,6 +364,23 @@ mod test { | |||
296 | } | 364 | } |
297 | 365 | ||
298 | #[test] | 366 | #[test] |
367 | fn make_usual_string_with_quote_works() { | ||
368 | check_assist( | ||
369 | make_usual_string, | ||
370 | r##" | ||
371 | fn f() { | ||
372 | let s = <|>r#"random"str"ing"#; | ||
373 | } | ||
374 | "##, | ||
375 | r#" | ||
376 | fn f() { | ||
377 | let s = <|>"random\"str\"ing"; | ||
378 | } | ||
379 | "#, | ||
380 | ) | ||
381 | } | ||
382 | |||
383 | #[test] | ||
299 | fn make_usual_string_more_hash_works() { | 384 | fn make_usual_string_more_hash_works() { |
300 | check_assist( | 385 | check_assist( |
301 | make_usual_string, | 386 | make_usual_string, |