aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src')
-rw-r--r--crates/ra_assists/src/assists/raw_string.rs59
1 files changed, 13 insertions, 46 deletions
diff --git a/crates/ra_assists/src/assists/raw_string.rs b/crates/ra_assists/src/assists/raw_string.rs
index 58f7157ae..93912a470 100644
--- a/crates/ra_assists/src/assists/raw_string.rs
+++ b/crates/ra_assists/src/assists/raw_string.rs
@@ -1,9 +1,9 @@
1use hir::db::HirDatabase; 1use hir::db::HirDatabase;
2use ra_syntax::{ 2use ra_syntax::{
3 ast, AstToken,
3 SyntaxKind::{RAW_STRING, STRING}, 4 SyntaxKind::{RAW_STRING, STRING},
4 TextRange, TextUnit, 5 TextUnit,
5}; 6};
6use rustc_lexer;
7 7
8use crate::{Assist, AssistCtx, AssistId}; 8use crate::{Assist, AssistCtx, AssistId};
9 9
@@ -23,32 +23,16 @@ use crate::{Assist, AssistCtx, AssistId};
23// } 23// }
24// ``` 24// ```
25pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 25pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
26 let token = ctx.find_token_at_offset(STRING)?; 26 let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?;
27 let text = token.text().as_str(); 27 let value = token.value()?;
28 let usual_string_range = find_usual_string_range(text)?;
29 let start_of_inside = usual_string_range.start().to_usize() + 1;
30 let end_of_inside = usual_string_range.end().to_usize();
31 let inside_str = &text[start_of_inside..end_of_inside];
32 let mut unescaped = String::with_capacity(inside_str.len());
33 let mut error = Ok(());
34 rustc_lexer::unescape::unescape_str(
35 inside_str,
36 &mut |_, unescaped_char| match unescaped_char {
37 Ok(c) => unescaped.push(c),
38 Err(_) => error = Err(()),
39 },
40 );
41 if error.is_err() {
42 return None;
43 }
44 ctx.add_assist(AssistId("make_raw_string"), "make raw string", |edit| { 28 ctx.add_assist(AssistId("make_raw_string"), "make raw string", |edit| {
45 edit.target(token.text_range()); 29 edit.target(token.syntax().text_range());
46 let max_hash_streak = count_hashes(&unescaped); 30 let max_hash_streak = count_hashes(&value);
47 let mut hashes = String::with_capacity(max_hash_streak + 1); 31 let mut hashes = String::with_capacity(max_hash_streak + 1);
48 for _ in 0..hashes.capacity() { 32 for _ in 0..hashes.capacity() {
49 hashes.push('#'); 33 hashes.push('#');
50 } 34 }
51 edit.replace(token.text_range(), format!("r{}\"{}\"{}", hashes, unescaped, hashes)); 35 edit.replace(token.syntax().text_range(), format!("r{}\"{}\"{}", hashes, value, hashes));
52 }) 36 })
53} 37}
54 38
@@ -68,17 +52,13 @@ pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
68// } 52// }
69// ``` 53// ```
70pub(crate) fn make_usual_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 54pub(crate) fn make_usual_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
71 let token = ctx.find_token_at_offset(RAW_STRING)?; 55 let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?;
72 let text = token.text().as_str(); 56 let value = token.value()?;
73 let usual_string_range = find_usual_string_range(text)?;
74 ctx.add_assist(AssistId("make_usual_string"), "make usual string", |edit| { 57 ctx.add_assist(AssistId("make_usual_string"), "make usual string", |edit| {
75 edit.target(token.text_range()); 58 edit.target(token.syntax().text_range());
76 // parse inside string to escape `"` 59 // parse inside string to escape `"`
77 let start_of_inside = usual_string_range.start().to_usize() + 1; 60 let escaped = value.escape_default().to_string();
78 let end_of_inside = usual_string_range.end().to_usize(); 61 edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped));
79 let inside_str = &text[start_of_inside..end_of_inside];
80 let escaped = inside_str.escape_default().to_string();
81 edit.replace(token.text_range(), format!("\"{}\"", escaped));
82 }) 62 })
83} 63}
84 64
@@ -132,6 +112,7 @@ pub(crate) fn remove_hash(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
132 edit.target(token.text_range()); 112 edit.target(token.text_range());
133 let result = &text[2..text.len() - 1]; 113 let result = &text[2..text.len() - 1];
134 let result = if result.starts_with('\"') { 114 let result = if result.starts_with('\"') {
115 // FIXME: this logic is wrong, not only the last has has to handled specially
135 // no more hash, escape 116 // no more hash, escape
136 let internal_str = &result[1..result.len() - 1]; 117 let internal_str = &result[1..result.len() - 1];
137 format!("\"{}\"", internal_str.escape_default().to_string()) 118 format!("\"{}\"", internal_str.escape_default().to_string())
@@ -154,20 +135,6 @@ fn count_hashes(s: &str) -> usize {
154 max_hash_streak 135 max_hash_streak
155} 136}
156 137
157fn find_usual_string_range(s: &str) -> Option<TextRange> {
158 let left_quote = s.find('"')?;
159 let right_quote = s.rfind('"')?;
160 if left_quote == right_quote {
161 // `s` only contains one quote
162 None
163 } else {
164 Some(TextRange::from_to(
165 TextUnit::from(left_quote as u32),
166 TextUnit::from(right_quote as u32),
167 ))
168 }
169}
170
171#[cfg(test)] 138#[cfg(test)]
172mod test { 139mod test {
173 use super::*; 140 use super::*;