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 --- Cargo.lock | 1 + crates/ra_assists/Cargo.toml | 1 + crates/ra_assists/src/assists/raw_string.rs | 77 +++++++++++++++++++++++++++++ crates/ra_assists/src/lib.rs | 2 +- docs/user/features.md | 15 ++++++ 5 files changed, 95 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 275b27775..dad9b1df1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -904,6 +904,7 @@ dependencies = [ "ra_syntax 0.1.0", "ra_text_edit 0.1.0", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_lexer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "test_utils 0.1.0", ] 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"); } - } diff --git a/docs/user/features.md b/docs/user/features.md index eb81cba26..fadd4cdf1 100644 --- a/docs/user/features.md +++ b/docs/user/features.md @@ -459,6 +459,21 @@ fn f() { } ``` +- Make raw string unescaped + +```rust +// before: +fn f() { + let s = <|>"ab\ncd"; +} + +// after: +fn f() { + let s = <|>r"ab +cd"; +} +``` + - Make usual string ```rust -- cgit v1.2.3