From 17a47a830bee9498874f17f2dc1cb688f8683a66 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 30 Jul 2021 16:46:06 +0200 Subject: [PATCH] Add replace_char_with_string assist --- .../src/handlers/replace_string_with_char.rs | 190 ++++++++++++++---- crates/ide_assists/src/lib.rs | 1 + crates/ide_assists/src/tests/generated.rs | 17 ++ 3 files changed, 171 insertions(+), 37 deletions(-) diff --git a/crates/ide_assists/src/handlers/replace_string_with_char.rs b/crates/ide_assists/src/handlers/replace_string_with_char.rs index 0800d291e44..a53f865a5e1 100644 --- a/crates/ide_assists/src/handlers/replace_string_with_char.rs +++ b/crates/ide_assists/src/handlers/replace_string_with_char.rs @@ -1,10 +1,16 @@ -use syntax::{ast, ast::IsString, AstToken, SyntaxKind::STRING}; +use syntax::{ + ast, + ast::IsString, + AstToken, + SyntaxKind::{CHAR, STRING}, + TextRange, TextSize, +}; use crate::{AssistContext, AssistId, AssistKind, Assists}; // Assist: replace_string_with_char // -// Replace string with char. +// Replace string literal with char literal. // // ``` // fn main() { @@ -33,31 +39,56 @@ pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext) - target, |edit| { let (left, right) = quote_offets.quotes; - edit.replace(left, String::from('\'')); - edit.replace(right, String::from('\'')); + edit.replace(left, '\''); + edit.replace(right, '\''); + if value == "'" { + edit.insert(left.end(), '\\'); + } + }, + ) +} + +// Assist: replace_char_with_string +// +// Replace a char literal with a string literal. +// +// ``` +// fn main() { +// find('{$0'); +// } +// ``` +// -> +// ``` +// fn main() { +// find("{"); +// } +// ``` +pub(crate) fn replace_char_with_string(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { + let token = ctx.find_token_syntax_at_offset(CHAR)?; + let target = token.text_range(); + + acc.add( + AssistId("replace_char_with_string", AssistKind::RefactorRewrite), + "Replace char with string", + target, + |edit| { + if token.text() == "'\"'" { + edit.replace(token.text_range(), r#""\"""#); + } else { + let len = TextSize::of('\''); + edit.replace(TextRange::at(target.start(), len), '"'); + edit.replace(TextRange::at(target.end() - len, len), '"'); + } }, ) } #[cfg(test)] mod tests { - use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; + use crate::tests::{check_assist, check_assist_not_applicable}; use super::*; - #[test] - fn replace_string_with_char_target() { - check_assist_target( - replace_string_with_char, - r#" -fn f() { - let s = "$0c"; -} -"#, - r#""c""#, - ); - } - #[test] fn replace_string_with_char_assist() { check_assist( @@ -76,7 +107,7 @@ fn f() { } #[test] - fn replace_string_with_char_assist_with_emoji() { + fn replace_string_with_char_assist_with_multi_byte_char() { check_assist( replace_string_with_char, r#" @@ -93,7 +124,7 @@ fn f() { } #[test] - fn replace_string_with_char_assist_not_applicable() { + fn replace_string_with_char_multiple_chars() { check_assist_not_applicable( replace_string_with_char, r#" @@ -121,23 +152,6 @@ fn f() { ) } - #[test] - fn replace_string_with_char_works_func_args() { - check_assist( - replace_string_with_char, - r#" -fn f() { - find($0"x"); -} -"#, - r##" -fn f() { - find('x'); -} -"##, - ) - } - #[test] fn replace_string_with_char_newline() { check_assist( @@ -188,4 +202,106 @@ fn f() { "##, ) } + + #[test] + fn replace_char_with_string_assist() { + check_assist( + replace_char_with_string, + r" +fn f() { + let s = '$0c'; +} +", + r#" +fn f() { + let s = "c"; +} +"#, + ) + } + + #[test] + fn replace_char_with_string_assist_with_multi_byte_char() { + check_assist( + replace_char_with_string, + r" +fn f() { + let s = '$0😀'; +} +", + r#" +fn f() { + let s = "😀"; +} +"#, + ) + } + + #[test] + fn replace_char_with_string_newline() { + check_assist( + replace_char_with_string, + r" +fn f() { + find($0'\n'); +} +", + r#" +fn f() { + find("\n"); +} +"#, + ) + } + + #[test] + fn replace_char_with_string_unicode_escape() { + check_assist( + replace_char_with_string, + r" +fn f() { + find($0'\u{7FFF}'); +} +", + r#" +fn f() { + find("\u{7FFF}"); +} +"#, + ) + } + + #[test] + fn replace_char_with_string_quote() { + check_assist( + replace_char_with_string, + r#" +fn f() { + find($0'"'); +} +"#, + r#" +fn f() { + find("\""); +} +"#, + ) + } + + #[test] + fn replace_string_with_char_quote() { + check_assist( + replace_string_with_char, + r#" +fn f() { + find($0"'"); +} +"#, + r#" +fn f() { + find('\''); +} +"#, + ) + } } diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs index 3c052a7de02..14bf565e565 100644 --- a/crates/ide_assists/src/lib.rs +++ b/crates/ide_assists/src/lib.rs @@ -194,6 +194,7 @@ mod handlers { add_missing_impl_members::add_missing_default_members, // replace_string_with_char::replace_string_with_char, + replace_string_with_char::replace_char_with_string, raw_string::make_raw_string, // extract_variable::extract_variable, diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs index 36ca7acfce9..ebf312aa3f8 100644 --- a/crates/ide_assists/src/tests/generated.rs +++ b/crates/ide_assists/src/tests/generated.rs @@ -1331,6 +1331,23 @@ impl Foo for Bar { ) } +#[test] +fn doctest_replace_char_with_string() { + check_doc_test( + "replace_char_with_string", + r#####" +fn main() { + find('{$0'); +} +"#####, + r#####" +fn main() { + find("{"); +} +"#####, + ) +} + #[test] fn doctest_replace_derive_with_manual_impl() { check_doc_test(