diff options
author | Aleksey Kladov <[email protected]> | 2019-11-16 19:50:41 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-11-16 19:50:41 +0000 |
commit | 5b54a93fe71137606674ff11dc57bc6e7eaa37f9 (patch) | |
tree | e3766c348d90f933b0f374b0a528e2ffc67d58fd /crates/ra_assists | |
parent | 42604c673d159edc1571732c6be1dc00a365b7be (diff) |
Add ast for plain and raw string literals
Diffstat (limited to 'crates/ra_assists')
-rw-r--r-- | crates/ra_assists/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_assists/src/assists/raw_string.rs | 59 |
2 files changed, 13 insertions, 47 deletions
diff --git a/crates/ra_assists/Cargo.toml b/crates/ra_assists/Cargo.toml index beebccbd9..125c6222d 100644 --- a/crates/ra_assists/Cargo.toml +++ b/crates/ra_assists/Cargo.toml | |||
@@ -8,7 +8,6 @@ authors = ["rust-analyzer developers"] | |||
8 | format-buf = "1.0.0" | 8 | format-buf = "1.0.0" |
9 | join_to_string = "0.1.3" | 9 | join_to_string = "0.1.3" |
10 | itertools = "0.8.0" | 10 | itertools = "0.8.0" |
11 | rustc_lexer = "0.1.0" | ||
12 | 11 | ||
13 | ra_syntax = { path = "../ra_syntax" } | 12 | ra_syntax = { path = "../ra_syntax" } |
14 | ra_text_edit = { path = "../ra_text_edit" } | 13 | ra_text_edit = { path = "../ra_text_edit" } |
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 @@ | |||
1 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | ast, AstToken, | ||
3 | SyntaxKind::{RAW_STRING, STRING}, | 4 | SyntaxKind::{RAW_STRING, STRING}, |
4 | TextRange, TextUnit, | 5 | TextUnit, |
5 | }; | 6 | }; |
6 | use rustc_lexer; | ||
7 | 7 | ||
8 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{Assist, AssistCtx, AssistId}; |
9 | 9 | ||
@@ -23,32 +23,16 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
23 | // } | 23 | // } |
24 | // ``` | 24 | // ``` |
25 | pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 25 | pub(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 | // ``` |
70 | pub(crate) fn make_usual_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 54 | pub(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 | ||
157 | fn 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)] |
172 | mod test { | 139 | mod test { |
173 | use super::*; | 140 | use super::*; |