Unnamed repository; edit this file 'description' to name the repository.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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::<ast::Literal>()?;
    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}'",
        );
    }
}
insert" = { fg = "bg", bg = "blue", modifiers = ["bold"] } "ui.statusline.select" = { fg = "bg", bg = "magenta", modifiers = ["bold"] } "ui.popup" = { bg = "gray01" } "ui.window" = { fg = "gray02" } "ui.help" = { bg = "gray01", fg = "white" } "ui.text" = { fg = "fg" } "ui.text.focus" = { fg = "fg" } "ui.virtual" = { fg = "gray02" } "ui.virtual.indent-guide" = { fg = "gray02" } "ui.selection" = { bg = "gray03" } "ui.selection.primary" = { bg = "gray03" } "ui.cursor" = { bg = "gray04" } "ui.cursor.match" = { fg = "yellow", modifiers = ["bold", "underlined"] } "ui.cursorline.primary" = { bg = "gray01" } "ui.highlight" = { bg = "gray02" } "ui.menu" = { fg = "white", bg = "gray01" } "ui.menu.selected" = { fg = "bright_white", bg = "gray03" } "ui.menu.scroll" = { fg = "gray04", bg = "gray01" } diagnostic = { modifiers = ["underlined"] } warning = "bright_yellow" error = "bright_red" info = "bright_blue" hint = "bright_cyan" [palette] bg = "#161617" fg = "#c9c7cd" bg_dark = "#131314" black = "#27272a" bright_black = "#353539" red = "#f5a191" bright_red = "#ffae9f" green = "#90b99f" bright_green = "#9dc6ac" yellow = "#e6b99d" bright_yellow = "#f0c5a9" blue = "#aca1cf" bright_blue = "#b9aeda" magenta = "#e29eca" bright_magenta = "#ecaad6" cyan = "#ea83a5" bright_cyan = "#f591b2" white = "#c1c0d4" bright_white = "#cac9dd" gray01 = "#1b1b1d" gray02 = "#2a2a2d" gray03 = "#3e3e43" gray04 = "#57575f" gray05 = "#757581" gray06 = "#9998a8" gray07 = "#c1c0d4"