From 281e1071558dff3138805de49dfbb0ad91b3acd3 Mon Sep 17 00:00:00 2001 From: Geobert Quach Date: Thu, 26 Sep 2019 20:31:45 +0100 Subject: feat(assists): Make raw string unescaped --- crates/ra_assists/Cargo.toml | 1 + crates/ra_assists/src/assists/raw_string.rs | 77 +++++++++++++++++++++++++++++ crates/ra_assists/src/lib.rs | 2 +- 3 files changed, 79 insertions(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_assists/Cargo.toml b/crates/ra_assists/Cargo.toml index 02966bbda..d3b6aeb36 100644 --- a/crates/ra_assists/Cargo.toml +++ b/crates/ra_assists/Cargo.toml @@ -11,6 +11,7 @@ join_to_string = "0.1.3" itertools = "0.8.0" arrayvec = "0.4.10" rustc-hash = "1.0.1" +rustc_lexer = "0.1.0" ra_syntax = { path = "../ra_syntax" } ra_text_edit = { path = "../ra_text_edit" } 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 @@ use hir::db::HirDatabase; use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; +use rustc_lexer; use crate::{Assist, AssistCtx, AssistId}; @@ -15,6 +16,39 @@ pub(crate) fn make_raw_string(mut ctx: AssistCtx) -> Option) -> Option { + let literal = ctx.node_at_offset::()?; + if literal.token().kind() != ra_syntax::SyntaxKind::STRING { + return None; + } + let token = literal.token(); + let text = token.text().as_str(); + if !text.contains(&['\\', '\r'][..]) { + return None; + } + let usual_string_range = find_usual_string_range(text)?; + ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| { + edit.target(literal.syntax().text_range()); + let start_of_inside = usual_string_range.start().to_usize() + 1; + let end_of_inside = usual_string_range.end().to_usize(); + let inside_str = &text[start_of_inside..end_of_inside]; + let mut unescaped = String::with_capacity(inside_str.len()); + let mut error = Ok(()); + rustc_lexer::unescape::unescape_str(inside_str, &mut |_, unescaped_char| { + match unescaped_char { + Ok(c) => unescaped.push(c), + Err(_) => error = Err(()), + } + }); + if error.is_err() { + eprintln!("Error unescaping string"); + } else { + edit.replace(literal.syntax().text_range(), format!("r\"{}\"", unescaped)); + } + }); + ctx.build() +} + fn find_usual_string_range(s: &str) -> Option { Some(TextRange::from_to( TextUnit::from(s.find('"')? as u32), @@ -145,6 +179,49 @@ mod test { ); } + #[test] + fn make_raw_string_unescaped_target() { + check_assist_target( + make_raw_string_unescaped, + r#" + fn f() { + let s = <|>"random\nstring"; + } + "#, + r#""random\nstring""#, + ); + } + + #[test] + fn make_raw_string_unescaped_works() { + check_assist( + make_raw_string_unescaped, + r#" + fn f() { + let s = <|>"random\nstring"; + } + "#, + r#" + fn f() { + let s = <|>r"random +string"; + } + "#, + ) + } + + #[test] + fn make_raw_string_unescaped_dont_works() { + check_assist_not_applicable( + make_raw_string_unescaped, + r#" + fn f() { + let s = <|>"random string"; + } + "#, + ) + } + #[test] fn add_hash_target() { check_assist_target( diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 897af2b02..d1e2d3251 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs @@ -132,6 +132,7 @@ mod assists { move_bounds::move_bounds_to_where_clause, raw_string::add_hash, raw_string::make_raw_string, + raw_string::make_raw_string_unescaped, raw_string::make_usual_string, raw_string::remove_hash, ] @@ -340,5 +341,4 @@ mod tests { assert_eq!(assists.next().expect("expected assist").0.label, "introduce variable"); assert_eq!(assists.next().expect("expected assist").0.label, "replace with match"); } - } -- cgit v1.2.3