use syntax::{AstToken, ast}; use crate::{AssistContext, AssistId, Assists, GroupLabel}; // Assist: convert_char_literal // // Converts character literals between different representations. Currently supports normal character -> ASCII / Unicode escape. // ``` // const _: char = 'a'$0; // ``` // -> // ``` // const _: char = '\x61'; // ``` pub(crate) fn convert_char_literal(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { if !ctx.has_empty_selection() { return None; } let literal = ctx.find_node_at_offset::()?; let literal = match literal.kind() { ast::LiteralKind::Char(it) => it, _ => return None, }; let value = literal.value().ok()?; let text = literal.syntax().text().to_owned(); let range = literal.syntax().text_range(); let group_id = GroupLabel("Convert char representation".into()); let mut add_assist = |converted: String| { // Skip no-op assists (e.g. `'const C: char = '\\x61';'` already matches the ASCII form). if converted == text { return; } let label = format!("Convert {text} to {converted}"); acc.add_group( &group_id, AssistId::refactor_rewrite("convert_char_literal"), label, range, |builder| builder.replace(range, converted), ); }; if value.is_ascii() { add_assist(format!("'\\x{:02x}'", value as u32)); } add_assist(format!("'\\u{{{:x}}}'", value as u32)); Some(()) } #[cfg(test)] mod tests { use crate::tests::check_assist_by_label; use super::convert_char_literal; #[test] fn ascii_char_to_ascii_and_unicode() { let before = "const _: char = 'a'$0;"; check_assist_by_label( convert_char_literal, before, "const _: char = '\\x61';", "Convert 'a' to '\\x61'", ); check_assist_by_label( convert_char_literal, before, "const _: char = '\\u{61}';", "Convert 'a' to '\\u{61}'", ); } #[test] fn non_ascii_char_only_unicode() { check_assist_by_label( convert_char_literal, "const _: char = '😀'$0;", "const _: char = '\\u{1f600}';", "Convert '😀' to '\\u{1f600}'", ); } #[test] fn ascii_escape_can_convert_to_unicode() { check_assist_by_label( convert_char_literal, "const _: char = '\\x61'$0;", "const _: char = '\\u{61}';", "Convert '\\x61' to '\\u{61}'", ); } }