Skip to content

Commit 04691ba

Browse files
authored
Merge pull request #21093 from Young-Flash/convert_char_literal
feat: add assist to convert char literal
2 parents 9422cf5 + 8169446 commit 04691ba

File tree

3 files changed

+112
-0
lines changed

3 files changed

+112
-0
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
use syntax::{AstToken, ast};
2+
3+
use crate::{AssistContext, AssistId, Assists, GroupLabel};
4+
5+
// Assist: convert_char_literal
6+
//
7+
// Converts character literals between different representations. Currently supports normal character -> ASCII / Unicode escape.
8+
// ```
9+
// const _: char = 'a'$0;
10+
// ```
11+
// ->
12+
// ```
13+
// const _: char = '\x61';
14+
// ```
15+
pub(crate) fn convert_char_literal(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
16+
if !ctx.has_empty_selection() {
17+
return None;
18+
}
19+
20+
let literal = ctx.find_node_at_offset::<ast::Literal>()?;
21+
let literal = match literal.kind() {
22+
ast::LiteralKind::Char(it) => it,
23+
_ => return None,
24+
};
25+
26+
let value = literal.value().ok()?;
27+
let text = literal.syntax().text().to_owned();
28+
let range = literal.syntax().text_range();
29+
let group_id = GroupLabel("Convert char representation".into());
30+
31+
let mut add_assist = |converted: String| {
32+
// Skip no-op assists (e.g. `'const C: char = '\\x61';'` already matches the ASCII form).
33+
if converted == text {
34+
return;
35+
}
36+
let label = format!("Convert {text} to {converted}");
37+
acc.add_group(
38+
&group_id,
39+
AssistId::refactor_rewrite("convert_char_literal"),
40+
label,
41+
range,
42+
|builder| builder.replace(range, converted),
43+
);
44+
};
45+
46+
if value.is_ascii() {
47+
add_assist(format!("'\\x{:02x}'", value as u32));
48+
}
49+
50+
add_assist(format!("'\\u{{{:x}}}'", value as u32));
51+
52+
Some(())
53+
}
54+
55+
#[cfg(test)]
56+
mod tests {
57+
use crate::tests::check_assist_by_label;
58+
59+
use super::convert_char_literal;
60+
61+
#[test]
62+
fn ascii_char_to_ascii_and_unicode() {
63+
let before = "const _: char = 'a'$0;";
64+
check_assist_by_label(
65+
convert_char_literal,
66+
before,
67+
"const _: char = '\\x61';",
68+
"Convert 'a' to '\\x61'",
69+
);
70+
check_assist_by_label(
71+
convert_char_literal,
72+
before,
73+
"const _: char = '\\u{61}';",
74+
"Convert 'a' to '\\u{61}'",
75+
);
76+
}
77+
78+
#[test]
79+
fn non_ascii_char_only_unicode() {
80+
check_assist_by_label(
81+
convert_char_literal,
82+
"const _: char = '😀'$0;",
83+
"const _: char = '\\u{1f600}';",
84+
"Convert '😀' to '\\u{1f600}'",
85+
);
86+
}
87+
88+
#[test]
89+
fn ascii_escape_can_convert_to_unicode() {
90+
check_assist_by_label(
91+
convert_char_literal,
92+
"const _: char = '\\x61'$0;",
93+
"const _: char = '\\u{61}';",
94+
"Convert '\\x61' to '\\u{61}'",
95+
);
96+
}
97+
}

crates/ide-assists/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ mod handlers {
119119
mod change_visibility;
120120
mod convert_bool_then;
121121
mod convert_bool_to_enum;
122+
mod convert_char_literal;
122123
mod convert_closure_to_fn;
123124
mod convert_comment_block;
124125
mod convert_comment_from_or_to_doc;
@@ -256,6 +257,7 @@ mod handlers {
256257
convert_bool_then::convert_bool_then_to_if,
257258
convert_bool_then::convert_if_to_bool_then,
258259
convert_bool_to_enum::convert_bool_to_enum,
260+
convert_char_literal::convert_char_literal,
259261
convert_closure_to_fn::convert_closure_to_fn,
260262
convert_comment_block::convert_comment_block,
261263
convert_comment_from_or_to_doc::convert_comment_from_or_to_doc,

crates/ide-assists/src/tests/generated.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,19 @@ fn main() {
424424
)
425425
}
426426

427+
#[test]
428+
fn doctest_convert_char_literal() {
429+
check_doc_test(
430+
"convert_char_literal",
431+
r#####"
432+
const _: char = 'a'$0;
433+
"#####,
434+
r#####"
435+
const _: char = '\x61';
436+
"#####,
437+
)
438+
}
439+
427440
#[test]
428441
fn doctest_convert_closure_to_fn() {
429442
check_doc_test(

0 commit comments

Comments
 (0)