aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists')
-rw-r--r--crates/ra_assists/src/raw_string.rs95
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 @@
1use hir::db::HirDatabase; 1use hir::db::HirDatabase;
2use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; 2use ra_syntax::{ast::AstNode, ast::Literal, SyntaxText, TextRange, TextUnit};
3 3
4use crate::{Assist, AssistCtx, AssistId}; 4use crate::{assist_ctx::AssistBuilder, Assist, AssistCtx, AssistId};
5 5
6pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 6pub(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
76fn 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
68pub(crate) fn remove_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 91pub(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,