Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/replace_string_with_char.rs')
| -rw-r--r-- | crates/ide-assists/src/handlers/replace_string_with_char.rs | 307 |
1 files changed, 307 insertions, 0 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 new file mode 100644 index 0000000000..a53f865a5e --- /dev/null +++ b/crates/ide-assists/src/handlers/replace_string_with_char.rs @@ -0,0 +1,307 @@ +use syntax::{ + ast, + ast::IsString, + AstToken, + SyntaxKind::{CHAR, STRING}, + TextRange, TextSize, +}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: replace_string_with_char +// +// Replace string literal with char literal. +// +// ``` +// fn main() { +// find("{$0"); +// } +// ``` +// -> +// ``` +// fn main() { +// find('{'); +// } +// ``` +pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { + let token = ctx.find_token_syntax_at_offset(STRING).and_then(ast::String::cast)?; + let value = token.value()?; + let target = token.syntax().text_range(); + + if value.chars().take(2).count() != 1 { + return None; + } + let quote_offets = token.quote_offsets()?; + + acc.add( + AssistId("replace_string_with_char", AssistKind::RefactorRewrite), + "Replace string with char", + target, + |edit| { + let (left, right) = quote_offets.quotes; + 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}; + + use super::*; + + #[test] + fn replace_string_with_char_assist() { + check_assist( + replace_string_with_char, + r#" +fn f() { + let s = "$0c"; +} +"#, + r##" +fn f() { + let s = 'c'; +} +"##, + ) + } + + #[test] + fn replace_string_with_char_assist_with_multi_byte_char() { + check_assist( + replace_string_with_char, + r#" +fn f() { + let s = "$0😀"; +} +"#, + r##" +fn f() { + let s = '😀'; +} +"##, + ) + } + + #[test] + fn replace_string_with_char_multiple_chars() { + check_assist_not_applicable( + replace_string_with_char, + r#" +fn f() { + let s = "$0test"; +} +"#, + ) + } + + #[test] + fn replace_string_with_char_works_inside_macros() { + check_assist( + replace_string_with_char, + r#" +fn f() { + format!($0"x", 92) +} +"#, + r##" +fn f() { + format!('x', 92) +} +"##, + ) + } + + #[test] + fn replace_string_with_char_newline() { + check_assist( + replace_string_with_char, + r#" +fn f() { + find($0"\n"); +} +"#, + r##" +fn f() { + find('\n'); +} +"##, + ) + } + + #[test] + fn replace_string_with_char_unicode_escape() { + check_assist( + replace_string_with_char, + r#" +fn f() { + find($0"\u{7FFF}"); +} +"#, + r##" +fn f() { + find('\u{7FFF}'); +} +"##, + ) + } + + #[test] + fn replace_raw_string_with_char() { + check_assist( + replace_string_with_char, + r##" +fn f() { + $0r#"X"# +} +"##, + r##" +fn f() { + 'X' +} +"##, + ) + } + + #[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('\''); +} +"#, + ) + } +} |