aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/assists/raw_string.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/assists/raw_string.rs')
-rw-r--r--crates/ra_assists/src/assists/raw_string.rs77
1 files changed, 77 insertions, 0 deletions
diff --git a/crates/ra_assists/src/assists/raw_string.rs b/crates/ra_assists/src/assists/raw_string.rs
index 965a64c98..fe396806b 100644
--- a/crates/ra_assists/src/assists/raw_string.rs
+++ b/crates/ra_assists/src/assists/raw_string.rs
@@ -1,5 +1,6 @@
1use hir::db::HirDatabase; 1use hir::db::HirDatabase;
2use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; 2use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit};
3use rustc_lexer;
3 4
4use crate::{Assist, AssistCtx, AssistId}; 5use crate::{Assist, AssistCtx, AssistId};
5 6
@@ -15,6 +16,39 @@ pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As
15 ctx.build() 16 ctx.build()
16} 17}
17 18
19pub(crate) fn make_raw_string_unescaped(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
20 let literal = ctx.node_at_offset::<Literal>()?;
21 if literal.token().kind() != ra_syntax::SyntaxKind::STRING {
22 return None;
23 }
24 let token = literal.token();
25 let text = token.text().as_str();
26 if !text.contains(&['\\', '\r'][..]) {
27 return None;
28 }
29 let usual_string_range = find_usual_string_range(text)?;
30 ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| {
31 edit.target(literal.syntax().text_range());
32 let start_of_inside = usual_string_range.start().to_usize() + 1;
33 let end_of_inside = usual_string_range.end().to_usize();
34 let inside_str = &text[start_of_inside..end_of_inside];
35 let mut unescaped = String::with_capacity(inside_str.len());
36 let mut error = Ok(());
37 rustc_lexer::unescape::unescape_str(inside_str, &mut |_, unescaped_char| {
38 match unescaped_char {
39 Ok(c) => unescaped.push(c),
40 Err(_) => error = Err(()),
41 }
42 });
43 if error.is_err() {
44 eprintln!("Error unescaping string");
45 } else {
46 edit.replace(literal.syntax().text_range(), format!("r\"{}\"", unescaped));
47 }
48 });
49 ctx.build()
50}
51
18fn find_usual_string_range(s: &str) -> Option<TextRange> { 52fn find_usual_string_range(s: &str) -> Option<TextRange> {
19 Some(TextRange::from_to( 53 Some(TextRange::from_to(
20 TextUnit::from(s.find('"')? as u32), 54 TextUnit::from(s.find('"')? as u32),
@@ -146,6 +180,49 @@ mod test {
146 } 180 }
147 181
148 #[test] 182 #[test]
183 fn make_raw_string_unescaped_target() {
184 check_assist_target(
185 make_raw_string_unescaped,
186 r#"
187 fn f() {
188 let s = <|>"random\nstring";
189 }
190 "#,
191 r#""random\nstring""#,
192 );
193 }
194
195 #[test]
196 fn make_raw_string_unescaped_works() {
197 check_assist(
198 make_raw_string_unescaped,
199 r#"
200 fn f() {
201 let s = <|>"random\nstring";
202 }
203 "#,
204 r#"
205 fn f() {
206 let s = <|>r"random
207string";
208 }
209 "#,
210 )
211 }
212
213 #[test]
214 fn make_raw_string_unescaped_dont_works() {
215 check_assist_not_applicable(
216 make_raw_string_unescaped,
217 r#"
218 fn f() {
219 let s = <|>"random string";
220 }
221 "#,
222 )
223 }
224
225 #[test]
149 fn add_hash_target() { 226 fn add_hash_target() {
150 check_assist_target( 227 check_assist_target(
151 add_hash, 228 add_hash,