diff options
Diffstat (limited to 'crates/ra_syntax/src/ast')
-rw-r--r-- | crates/ra_syntax/src/ast/edit.rs | 11 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/make.rs | 11 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/tokens.rs | 110 |
3 files changed, 89 insertions, 43 deletions
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs index 0e78d8b63..d2630e9e9 100644 --- a/crates/ra_syntax/src/ast/edit.rs +++ b/crates/ra_syntax/src/ast/edit.rs | |||
@@ -276,7 +276,7 @@ pub fn replace_descendants<N: AstNode, D: AstNode>( | |||
276 | .into_iter() | 276 | .into_iter() |
277 | .map(|(from, to)| (from.syntax().clone().into(), to.syntax().clone().into())) | 277 | .map(|(from, to)| (from.syntax().clone().into(), to.syntax().clone().into())) |
278 | .collect::<FxHashMap<SyntaxElement, _>>(); | 278 | .collect::<FxHashMap<SyntaxElement, _>>(); |
279 | let new_syntax = algo::replace_descendants(parent.syntax(), &|n| map.get(n).cloned()); | 279 | let new_syntax = algo::replace_descendants(parent.syntax(), |n| map.get(n).cloned()); |
280 | N::cast(new_syntax).unwrap() | 280 | N::cast(new_syntax).unwrap() |
281 | } | 281 | } |
282 | 282 | ||
@@ -331,7 +331,7 @@ impl IndentLevel { | |||
331 | ) | 331 | ) |
332 | }) | 332 | }) |
333 | .collect(); | 333 | .collect(); |
334 | algo::replace_descendants(&node, &|n| replacements.get(n).cloned()) | 334 | algo::replace_descendants(&node, |n| replacements.get(n).cloned()) |
335 | } | 335 | } |
336 | 336 | ||
337 | pub fn decrease_indent<N: AstNode>(self, node: N) -> N { | 337 | pub fn decrease_indent<N: AstNode>(self, node: N) -> N { |
@@ -359,7 +359,7 @@ impl IndentLevel { | |||
359 | ) | 359 | ) |
360 | }) | 360 | }) |
361 | .collect(); | 361 | .collect(); |
362 | algo::replace_descendants(&node, &|n| replacements.get(n).cloned()) | 362 | algo::replace_descendants(&node, |n| replacements.get(n).cloned()) |
363 | } | 363 | } |
364 | } | 364 | } |
365 | 365 | ||
@@ -389,7 +389,7 @@ fn insert_children<N: AstNode>( | |||
389 | position: InsertPosition<SyntaxElement>, | 389 | position: InsertPosition<SyntaxElement>, |
390 | to_insert: impl IntoIterator<Item = SyntaxElement>, | 390 | to_insert: impl IntoIterator<Item = SyntaxElement>, |
391 | ) -> N { | 391 | ) -> N { |
392 | let new_syntax = algo::insert_children(parent.syntax(), position, &mut to_insert.into_iter()); | 392 | let new_syntax = algo::insert_children(parent.syntax(), position, to_insert); |
393 | N::cast(new_syntax).unwrap() | 393 | N::cast(new_syntax).unwrap() |
394 | } | 394 | } |
395 | 395 | ||
@@ -404,8 +404,7 @@ fn replace_children<N: AstNode>( | |||
404 | to_replace: RangeInclusive<SyntaxElement>, | 404 | to_replace: RangeInclusive<SyntaxElement>, |
405 | to_insert: impl IntoIterator<Item = SyntaxElement>, | 405 | to_insert: impl IntoIterator<Item = SyntaxElement>, |
406 | ) -> N { | 406 | ) -> N { |
407 | let new_syntax = | 407 | let new_syntax = algo::replace_children(parent.syntax(), to_replace, to_insert); |
408 | algo::replace_children(parent.syntax(), to_replace, &mut to_insert.into_iter()); | ||
409 | N::cast(new_syntax).unwrap() | 408 | N::cast(new_syntax).unwrap() |
410 | } | 409 | } |
411 | 410 | ||
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index 7c20fcc10..3f11b747f 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs | |||
@@ -12,11 +12,14 @@ pub fn name_ref(text: &str) -> ast::NameRef { | |||
12 | ast_from_text(&format!("fn f() {{ {}; }}", text)) | 12 | ast_from_text(&format!("fn f() {{ {}; }}", text)) |
13 | } | 13 | } |
14 | 14 | ||
15 | pub fn path_from_name_ref(name_ref: ast::NameRef) -> ast::Path { | 15 | pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment { |
16 | path_from_text(&name_ref.syntax().to_string()) | 16 | ast_from_text(&format!("use {};", name_ref.syntax())) |
17 | } | 17 | } |
18 | pub fn path_qualified(qual: ast::Path, name_ref: ast::NameRef) -> ast::Path { | 18 | pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path { |
19 | path_from_text(&format!("{}::{}", qual.syntax(), name_ref.syntax())) | 19 | path_from_text(&format!("use {}", segment.syntax())) |
20 | } | ||
21 | pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { | ||
22 | path_from_text(&format!("{}::{}", qual.syntax(), segment.syntax())) | ||
20 | } | 23 | } |
21 | fn path_from_text(text: &str) -> ast::Path { | 24 | fn path_from_text(text: &str) -> ast::Path { |
22 | ast_from_text(text) | 25 | ast_from_text(text) |
diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs index ed8661faf..1a51b8d3b 100644 --- a/crates/ra_syntax/src/ast/tokens.rs +++ b/crates/ra_syntax/src/ast/tokens.rs | |||
@@ -110,6 +110,64 @@ impl Whitespace { | |||
110 | } | 110 | } |
111 | } | 111 | } |
112 | 112 | ||
113 | pub struct QuoteOffsets { | ||
114 | pub quotes: [TextRange; 2], | ||
115 | pub contents: TextRange, | ||
116 | } | ||
117 | |||
118 | impl QuoteOffsets { | ||
119 | fn new(literal: &str) -> Option<QuoteOffsets> { | ||
120 | let left_quote = literal.find('"')?; | ||
121 | let right_quote = literal.rfind('"')?; | ||
122 | if left_quote == right_quote { | ||
123 | // `literal` only contains one quote | ||
124 | return None; | ||
125 | } | ||
126 | |||
127 | let start = TextUnit::from(0); | ||
128 | let left_quote = TextUnit::from_usize(left_quote) + TextUnit::of_char('"'); | ||
129 | let right_quote = TextUnit::from_usize(right_quote); | ||
130 | let end = TextUnit::of_str(literal); | ||
131 | |||
132 | let res = QuoteOffsets { | ||
133 | quotes: [TextRange::from_to(start, left_quote), TextRange::from_to(right_quote, end)], | ||
134 | contents: TextRange::from_to(left_quote, right_quote), | ||
135 | }; | ||
136 | Some(res) | ||
137 | } | ||
138 | } | ||
139 | |||
140 | pub trait HasQuotes: AstToken { | ||
141 | fn quote_offsets(&self) -> Option<QuoteOffsets> { | ||
142 | let text = self.text().as_str(); | ||
143 | let offsets = QuoteOffsets::new(text)?; | ||
144 | let o = self.syntax().text_range().start(); | ||
145 | let offsets = QuoteOffsets { | ||
146 | quotes: [offsets.quotes[0] + o, offsets.quotes[1] + o], | ||
147 | contents: offsets.contents + o, | ||
148 | }; | ||
149 | Some(offsets) | ||
150 | } | ||
151 | fn open_quote_text_range(&self) -> Option<TextRange> { | ||
152 | self.quote_offsets().map(|it| it.quotes[0]) | ||
153 | } | ||
154 | |||
155 | fn close_quote_text_range(&self) -> Option<TextRange> { | ||
156 | self.quote_offsets().map(|it| it.quotes[1]) | ||
157 | } | ||
158 | |||
159 | fn text_range_between_quotes(&self) -> Option<TextRange> { | ||
160 | self.quote_offsets().map(|it| it.contents) | ||
161 | } | ||
162 | } | ||
163 | |||
164 | impl HasQuotes for String {} | ||
165 | impl HasQuotes for RawString {} | ||
166 | |||
167 | pub trait HasStringValue: HasQuotes { | ||
168 | fn value(&self) -> Option<std::string::String>; | ||
169 | } | ||
170 | |||
113 | pub struct String(SyntaxToken); | 171 | pub struct String(SyntaxToken); |
114 | 172 | ||
115 | impl AstToken for String { | 173 | impl AstToken for String { |
@@ -124,21 +182,16 @@ impl AstToken for String { | |||
124 | } | 182 | } |
125 | } | 183 | } |
126 | 184 | ||
127 | impl String { | 185 | impl HasStringValue for String { |
128 | pub fn value(&self) -> Option<std::string::String> { | 186 | fn value(&self) -> Option<std::string::String> { |
129 | let text = self.text().as_str(); | 187 | let text = self.text().as_str(); |
130 | let usual_string_range = find_usual_string_range(text)?; | 188 | let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; |
131 | let start_of_inside = usual_string_range.start().to_usize() + 1; | ||
132 | let end_of_inside = usual_string_range.end().to_usize(); | ||
133 | let inside_str = &text[start_of_inside..end_of_inside]; | ||
134 | 189 | ||
135 | let mut buf = std::string::String::with_capacity(inside_str.len()); | 190 | let mut buf = std::string::String::with_capacity(text.len()); |
136 | let mut has_error = false; | 191 | let mut has_error = false; |
137 | rustc_lexer::unescape::unescape_str(inside_str, &mut |_, unescaped_char| { | 192 | rustc_lexer::unescape::unescape_str(text, &mut |_, unescaped_char| match unescaped_char { |
138 | match unescaped_char { | 193 | Ok(c) => buf.push(c), |
139 | Ok(c) => buf.push(c), | 194 | Err(_) => has_error = true, |
140 | Err(_) => has_error = true, | ||
141 | } | ||
142 | }); | 195 | }); |
143 | 196 | ||
144 | if has_error { | 197 | if has_error { |
@@ -162,27 +215,18 @@ impl AstToken for RawString { | |||
162 | } | 215 | } |
163 | } | 216 | } |
164 | 217 | ||
165 | impl RawString { | 218 | impl HasStringValue for RawString { |
166 | pub fn value(&self) -> Option<std::string::String> { | 219 | fn value(&self) -> Option<std::string::String> { |
167 | let text = self.text().as_str(); | 220 | let text = self.text().as_str(); |
168 | let usual_string_range = find_usual_string_range(text)?; | 221 | let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; |
169 | let start_of_inside = usual_string_range.start().to_usize() + 1; | 222 | Some(text.to_string()) |
170 | let end_of_inside = usual_string_range.end().to_usize(); | 223 | } |
171 | let inside_str = &text[start_of_inside..end_of_inside]; | 224 | } |
172 | Some(inside_str.to_string()) | 225 | |
173 | } | 226 | impl RawString { |
174 | } | 227 | pub fn map_range_up(&self, range: TextRange) -> Option<TextRange> { |
175 | 228 | let contents_range = self.text_range_between_quotes()?; | |
176 | fn find_usual_string_range(s: &str) -> Option<TextRange> { | 229 | assert!(range.is_subrange(&TextRange::offset_len(0.into(), contents_range.len()))); |
177 | let left_quote = s.find('"')?; | 230 | Some(range + contents_range.start()) |
178 | let right_quote = s.rfind('"')?; | ||
179 | if left_quote == right_quote { | ||
180 | // `s` only contains one quote | ||
181 | None | ||
182 | } else { | ||
183 | Some(TextRange::from_to( | ||
184 | TextUnit::from(left_quote as u32), | ||
185 | TextUnit::from(right_quote as u32), | ||
186 | )) | ||
187 | } | 231 | } |
188 | } | 232 | } |