Skip to content

Commit b6d5529

Browse files
author
Geobert Quach
committed
feat(assists): raw string <-> usual string manipulation
Fixes #1730
1 parent 58dc3b1 commit b6d5529

File tree

3 files changed

+387
-0
lines changed

3 files changed

+387
-0
lines changed

crates/ra_assists/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ mod fill_match_arms;
9696
mod merge_match_arms;
9797
mod introduce_variable;
9898
mod inline_local_variable;
99+
mod raw_string;
99100
mod replace_if_let_with_match;
100101
mod split_import;
101102
mod remove_dbg;
@@ -125,6 +126,10 @@ fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assis
125126
move_guard::move_guard_to_arm_body,
126127
move_guard::move_arm_cond_to_match_guard,
127128
move_bounds::move_bounds_to_where_clause,
129+
raw_string::add_hash,
130+
raw_string::make_raw_string,
131+
raw_string::make_usual_string,
132+
raw_string::remove_hash,
128133
]
129134
}
130135

crates/ra_assists/src/raw_string.rs

+326
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
use hir::db::HirDatabase;
2+
use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit};
3+
4+
use crate::{Assist, AssistCtx, AssistId};
5+
6+
pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
7+
let literal = ctx.node_at_offset::<Literal>()?;
8+
if literal.token().kind() == ra_syntax::SyntaxKind::STRING {
9+
ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| {
10+
edit.target(literal.syntax().text_range());
11+
edit.insert(literal.syntax().text_range().start(), "r");
12+
});
13+
ctx.build()
14+
} else {
15+
None
16+
}
17+
}
18+
19+
pub(crate) fn make_usual_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
20+
let literal = ctx.node_at_offset::<Literal>()?;
21+
if literal.token().kind() == ra_syntax::SyntaxKind::RAW_STRING {
22+
ctx.add_action(AssistId("make_usual_string"), "make usual string", |edit| {
23+
let text = literal.syntax().text();
24+
let usual_start_pos = text.find_char('"').unwrap(); // we have a RAW_STRING
25+
let end = literal.syntax().text_range().end();
26+
dbg!(&end);
27+
let mut i = 0;
28+
let mut pos = 0;
29+
let mut c = text.char_at(end - TextUnit::from(i));
30+
while c != Some('"') {
31+
if c != None {
32+
pos += 1;
33+
}
34+
i += 1;
35+
c = text.char_at(end - TextUnit::from(i));
36+
}
37+
38+
edit.target(literal.syntax().text_range());
39+
edit.delete(TextRange::from_to(
40+
literal.syntax().text_range().start(),
41+
literal.syntax().text_range().start() + usual_start_pos,
42+
));
43+
edit.delete(TextRange::from_to(
44+
literal.syntax().text_range().end() - TextUnit::from(pos),
45+
literal.syntax().text_range().end(),
46+
));
47+
});
48+
ctx.build()
49+
} else {
50+
None
51+
}
52+
}
53+
54+
pub(crate) fn add_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
55+
let literal = ctx.node_at_offset::<Literal>()?;
56+
if literal.token().kind() == ra_syntax::SyntaxKind::RAW_STRING {
57+
ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| {
58+
edit.target(literal.syntax().text_range());
59+
edit.insert(literal.syntax().text_range().start() + TextUnit::from(1), "#");
60+
edit.insert(literal.syntax().text_range().end(), "#");
61+
});
62+
ctx.build()
63+
} else {
64+
None
65+
}
66+
}
67+
68+
pub(crate) fn remove_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
69+
let literal = ctx.node_at_offset::<Literal>()?;
70+
if literal.token().kind() == ra_syntax::SyntaxKind::RAW_STRING {
71+
if !literal.syntax().text().contains_char('#') {
72+
return None;
73+
}
74+
ctx.add_action(AssistId("remove_hash"), "remove hash from raw string", |edit| {
75+
edit.target(literal.syntax().text_range());
76+
edit.delete(TextRange::from_to(
77+
literal.syntax().text_range().start() + TextUnit::from(1),
78+
literal.syntax().text_range().start() + TextUnit::from(2),
79+
));
80+
edit.delete(TextRange::from_to(
81+
literal.syntax().text_range().end() - TextUnit::from(1),
82+
literal.syntax().text_range().end(),
83+
));
84+
});
85+
ctx.build()
86+
} else {
87+
None
88+
}
89+
}
90+
91+
#[cfg(test)]
92+
mod test {
93+
use super::*;
94+
use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target};
95+
96+
#[test]
97+
fn make_raw_string_target() {
98+
check_assist_target(
99+
make_raw_string,
100+
r#"
101+
fn f() {
102+
let s = <|>"random string";
103+
}
104+
"#,
105+
r#""random string""#,
106+
);
107+
}
108+
109+
#[test]
110+
fn make_raw_string_works() {
111+
check_assist(
112+
make_raw_string,
113+
r#"
114+
fn f() {
115+
let s = <|>"random string";
116+
}
117+
"#,
118+
r#"
119+
fn f() {
120+
let s = <|>r"random string";
121+
}
122+
"#,
123+
)
124+
}
125+
126+
#[test]
127+
fn make_raw_string_not_works() {
128+
check_assist_not_applicable(
129+
make_raw_string,
130+
r#"
131+
fn f() {
132+
let s = <|>r"random string";
133+
}
134+
"#,
135+
);
136+
}
137+
138+
#[test]
139+
fn add_hash_target() {
140+
check_assist_target(
141+
add_hash,
142+
r#"
143+
fn f() {
144+
let s = <|>r"random string";
145+
}
146+
"#,
147+
r#"r"random string""#,
148+
);
149+
}
150+
151+
#[test]
152+
fn add_hash_works() {
153+
check_assist(
154+
add_hash,
155+
r#"
156+
fn f() {
157+
let s = <|>r"random string";
158+
}
159+
"#,
160+
r##"
161+
fn f() {
162+
let s = <|>r#"random string"#;
163+
}
164+
"##,
165+
)
166+
}
167+
168+
#[test]
169+
fn add_more_hash_works() {
170+
check_assist(
171+
add_hash,
172+
r##"
173+
fn f() {
174+
let s = <|>r#"random string"#;
175+
}
176+
"##,
177+
r###"
178+
fn f() {
179+
let s = <|>r##"random string"##;
180+
}
181+
"###,
182+
)
183+
}
184+
185+
#[test]
186+
fn add_hash_not_works() {
187+
check_assist_not_applicable(
188+
add_hash,
189+
r#"
190+
fn f() {
191+
let s = <|>"random string";
192+
}
193+
"#,
194+
);
195+
}
196+
197+
#[test]
198+
fn remove_hash_target() {
199+
check_assist_target(
200+
remove_hash,
201+
r##"
202+
fn f() {
203+
let s = <|>r#"random string"#;
204+
}
205+
"##,
206+
r##"r#"random string"#"##,
207+
);
208+
}
209+
210+
#[test]
211+
fn remove_hash_works() {
212+
check_assist(
213+
remove_hash,
214+
r##"
215+
fn f() {
216+
let s = <|>r#"random string"#;
217+
}
218+
"##,
219+
r#"
220+
fn f() {
221+
let s = <|>r"random string";
222+
}
223+
"#,
224+
)
225+
}
226+
227+
#[test]
228+
fn remove_more_hash_works() {
229+
check_assist(
230+
remove_hash,
231+
r###"
232+
fn f() {
233+
let s = <|>r##"random string"##;
234+
}
235+
"###,
236+
r##"
237+
fn f() {
238+
let s = <|>r#"random string"#;
239+
}
240+
"##,
241+
)
242+
}
243+
244+
#[test]
245+
fn remove_hash_not_works() {
246+
check_assist_not_applicable(
247+
remove_hash,
248+
r#"
249+
fn f() {
250+
let s = <|>"random string";
251+
}
252+
"#,
253+
);
254+
}
255+
256+
#[test]
257+
fn remove_hash_no_hash_not_works() {
258+
check_assist_not_applicable(
259+
remove_hash,
260+
r#"
261+
fn f() {
262+
let s = <|>r"random string";
263+
}
264+
"#,
265+
);
266+
}
267+
268+
#[test]
269+
fn make_usual_string_target() {
270+
check_assist_target(
271+
make_usual_string,
272+
r##"
273+
fn f() {
274+
let s = <|>r#"random string"#;
275+
}
276+
"##,
277+
r##"r#"random string"#"##,
278+
);
279+
}
280+
281+
#[test]
282+
fn make_usual_string_works() {
283+
check_assist(
284+
make_usual_string,
285+
r##"
286+
fn f() {
287+
let s = <|>r#"random string"#;
288+
}
289+
"##,
290+
r#"
291+
fn f() {
292+
let s = <|>"random string";
293+
}
294+
"#,
295+
)
296+
}
297+
298+
#[test]
299+
fn make_usual_string_more_hash_works() {
300+
check_assist(
301+
make_usual_string,
302+
r###"
303+
fn f() {
304+
let s = <|>r##"random string"##;
305+
}
306+
"###,
307+
r##"
308+
fn f() {
309+
let s = <|>"random string";
310+
}
311+
"##,
312+
)
313+
}
314+
315+
#[test]
316+
fn make_usual_string_not_works() {
317+
check_assist_not_applicable(
318+
make_usual_string,
319+
r#"
320+
fn f() {
321+
let s = <|>"random string";
322+
}
323+
"#,
324+
);
325+
}
326+
}

0 commit comments

Comments
 (0)