diff --git a/Cargo.lock b/Cargo.lock index a5a43cffc4..e9383a89a8 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 02966bbda3..d3b6aeb36a 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 388ee7e97b..2d2e31e513 100644 --- a/crates/ra_assists/src/assists/raw_string.rs +++ b/crates/ra_assists/src/assists/raw_string.rs @@ -2,6 +2,7 @@ use hir::db::HirDatabase; use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; +use rustc_lexer; use crate::{Assist, AssistCtx, AssistId}; @@ -10,13 +11,51 @@ pub(crate) fn make_raw_string(mut ctx: AssistCtx) -> Option unescaped.push(c), + Err(_) => error = Err(()), + }, + ); + if error.is_err() { + return None; + } ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| { edit.target(literal.syntax().text_range()); - edit.insert(literal.syntax().text_range().start(), "r"); + let max_hash_streak = count_hashes(&unescaped); + let mut hashes = String::with_capacity(max_hash_streak + 1); + for _ in 0..hashes.capacity() { + hashes.push('#'); + } + edit.replace( + literal.syntax().text_range(), + format!("r{}\"{}\"{}", hashes, unescaped, hashes), + ); }); ctx.build() } +fn count_hashes(s: &str) -> usize { + let mut max_hash_streak = 0usize; + for idx in s.match_indices("\"#").map(|(i, _)| i) { + let (_, sub) = s.split_at(idx + 1); + let nb_hash = sub.chars().take_while(|c| *c == '#').count(); + if nb_hash > max_hash_streak { + max_hash_streak = nb_hash; + } + } + max_hash_streak +} + fn find_usual_string_range(s: &str) -> Option { Some(TextRange::from_to( TextUnit::from(s.find('"')? as u32), @@ -94,10 +133,10 @@ mod test { make_raw_string, r#" fn f() { - let s = <|>"random string"; + let s = <|>"random\nstring"; } "#, - r#""random string""#, + r#""random\nstring""#, ); } @@ -107,46 +146,71 @@ mod test { make_raw_string, r#" fn f() { - let s = <|>"random string"; + let s = <|>"random\nstring"; } "#, - r#" + r##" fn f() { - let s = <|>r"random string"; + let s = <|>r#"random +string"#; } - "#, + "##, ) } #[test] - fn make_raw_string_with_escaped_works() { + fn make_raw_string_hashes_inside_works() { + check_assist( + make_raw_string, + r###" + fn f() { + let s = <|>"#random##\nstring"; + } + "###, + r####" + fn f() { + let s = <|>r#"#random## +string"#; + } + "####, + ) + } + + #[test] + fn make_raw_string_closing_hashes_inside_works() { + check_assist( + make_raw_string, + r###" + fn f() { + let s = <|>"#random\"##\nstring"; + } + "###, + r####" + fn f() { + let s = <|>r###"#random"## +string"###; + } + "####, + ) + } + + #[test] + fn make_raw_string_nothing_to_unescape_works() { check_assist( make_raw_string, r#" fn f() { - let s = <|>"random\nstring"; + let s = <|>"random string"; } "#, - r#" + r##" fn f() { - let s = <|>r"random\nstring"; + let s = <|>r#"random string"#; } - "#, + "##, ) } - #[test] - fn make_raw_string_not_works() { - check_assist_not_applicable( - make_raw_string, - r#" - fn f() { - let s = <|>r"random string"; - } - "#, - ); - } - #[test] fn add_hash_target() { check_assist_target( @@ -369,4 +433,14 @@ mod test { "#, ); } + + #[test] + fn count_hashes_test() { + assert_eq!(0, count_hashes("abc")); + assert_eq!(0, count_hashes("###")); + assert_eq!(1, count_hashes("\"#abc")); + assert_eq!(0, count_hashes("#abc")); + assert_eq!(2, count_hashes("#ab\"##c")); + assert_eq!(4, count_hashes("#ab\"##\"####c")); + } } diff --git a/docs/user/features.md b/docs/user/features.md index 757a02838e..8b7a8d7fc1 100644 --- a/docs/user/features.md +++ b/docs/user/features.md @@ -459,17 +459,18 @@ fn foo T>() {} fn foo() where T: u32, F: FnOnce(T) -> T {} ``` -- Make raw string +- Make raw string unescaped ```rust // before: fn f() { - let s = <|>"abcd"; + let s = <|>"ab\ncd"; } // after: fn f() { - let s = <|>r"abcd"; + let s = <|>r#"ab +cd"#; } ```