aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/ast/tokens.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/ast/tokens.rs')
-rw-r--r--crates/ra_syntax/src/ast/tokens.rs69
1 files changed, 39 insertions, 30 deletions
diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs
index 3cd6d99c3..045f69133 100644
--- a/crates/ra_syntax/src/ast/tokens.rs
+++ b/crates/ra_syntax/src/ast/tokens.rs
@@ -1,6 +1,9 @@
1//! There are many AstNodes, but only a few tokens, so we hand-write them here. 1//! There are many AstNodes, but only a few tokens, so we hand-write them here.
2 2
3use std::convert::{TryFrom, TryInto}; 3use std::{
4 borrow::Cow,
5 convert::{TryFrom, TryInto},
6};
4 7
5use crate::{ 8use crate::{
6 ast::{AstToken, Comment, RawString, String, Whitespace}, 9 ast::{AstToken, Comment, RawString, String, Whitespace},
@@ -84,7 +87,7 @@ impl Whitespace {
84} 87}
85 88
86pub struct QuoteOffsets { 89pub struct QuoteOffsets {
87 pub quotes: [TextRange; 2], 90 pub quotes: (TextRange, TextRange),
88 pub contents: TextRange, 91 pub contents: TextRange,
89} 92}
90 93
@@ -103,7 +106,7 @@ impl QuoteOffsets {
103 let end = TextSize::of(literal); 106 let end = TextSize::of(literal);
104 107
105 let res = QuoteOffsets { 108 let res = QuoteOffsets {
106 quotes: [TextRange::new(start, left_quote), TextRange::new(right_quote, end)], 109 quotes: (TextRange::new(start, left_quote), TextRange::new(right_quote, end)),
107 contents: TextRange::new(left_quote, right_quote), 110 contents: TextRange::new(left_quote, right_quote),
108 }; 111 };
109 Some(res) 112 Some(res)
@@ -116,17 +119,17 @@ pub trait HasQuotes: AstToken {
116 let offsets = QuoteOffsets::new(text)?; 119 let offsets = QuoteOffsets::new(text)?;
117 let o = self.syntax().text_range().start(); 120 let o = self.syntax().text_range().start();
118 let offsets = QuoteOffsets { 121 let offsets = QuoteOffsets {
119 quotes: [offsets.quotes[0] + o, offsets.quotes[1] + o], 122 quotes: (offsets.quotes.0 + o, offsets.quotes.1 + o),
120 contents: offsets.contents + o, 123 contents: offsets.contents + o,
121 }; 124 };
122 Some(offsets) 125 Some(offsets)
123 } 126 }
124 fn open_quote_text_range(&self) -> Option<TextRange> { 127 fn open_quote_text_range(&self) -> Option<TextRange> {
125 self.quote_offsets().map(|it| it.quotes[0]) 128 self.quote_offsets().map(|it| it.quotes.0)
126 } 129 }
127 130
128 fn close_quote_text_range(&self) -> Option<TextRange> { 131 fn close_quote_text_range(&self) -> Option<TextRange> {
129 self.quote_offsets().map(|it| it.quotes[1]) 132 self.quote_offsets().map(|it| it.quotes.1)
130 } 133 }
131 134
132 fn text_range_between_quotes(&self) -> Option<TextRange> { 135 fn text_range_between_quotes(&self) -> Option<TextRange> {
@@ -138,11 +141,11 @@ impl HasQuotes for String {}
138impl HasQuotes for RawString {} 141impl HasQuotes for RawString {}
139 142
140pub trait HasStringValue: HasQuotes { 143pub trait HasStringValue: HasQuotes {
141 fn value(&self) -> Option<std::string::String>; 144 fn value(&self) -> Option<Cow<'_, str>>;
142} 145}
143 146
144impl HasStringValue for String { 147impl HasStringValue for String {
145 fn value(&self) -> Option<std::string::String> { 148 fn value(&self) -> Option<Cow<'_, str>> {
146 let text = self.text().as_str(); 149 let text = self.text().as_str();
147 let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; 150 let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
148 151
@@ -156,15 +159,17 @@ impl HasStringValue for String {
156 if has_error { 159 if has_error {
157 return None; 160 return None;
158 } 161 }
159 Some(buf) 162 // FIXME: don't actually allocate for borrowed case
163 let res = if buf == text { Cow::Borrowed(text) } else { Cow::Owned(buf) };
164 Some(res)
160 } 165 }
161} 166}
162 167
163impl HasStringValue for RawString { 168impl HasStringValue for RawString {
164 fn value(&self) -> Option<std::string::String> { 169 fn value(&self) -> Option<Cow<'_, str>> {
165 let text = self.text().as_str(); 170 let text = self.text().as_str();
166 let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; 171 let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
167 Some(text.to_string()) 172 Some(Cow::Borrowed(text))
168 } 173 }
169} 174}
170 175
@@ -335,16 +340,26 @@ pub trait HasFormatSpecifier: AstToken {
335 } 340 }
336 c if c == '_' || c.is_alphabetic() => { 341 c if c == '_' || c.is_alphabetic() => {
337 read_identifier(&mut chars, &mut callback); 342 read_identifier(&mut chars, &mut callback);
338 if chars.peek().and_then(|next| next.1.as_ref().ok()).copied() 343 // can be either width (indicated by dollar sign, or type in which case
339 != Some('$') 344 // the next sign has to be `}`)
340 { 345 let next =
341 continue; 346 chars.peek().and_then(|next| next.1.as_ref().ok()).copied();
342 } 347 match next {
343 skip_char_and_emit( 348 Some('$') => skip_char_and_emit(
344 &mut chars, 349 &mut chars,
345 FormatSpecifier::DollarSign, 350 FormatSpecifier::DollarSign,
346 &mut callback, 351 &mut callback,
347 ); 352 ),
353 Some('}') => {
354 skip_char_and_emit(
355 &mut chars,
356 FormatSpecifier::Close,
357 &mut callback,
358 );
359 continue;
360 }
361 _ => continue,
362 };
348 } 363 }
349 _ => {} 364 _ => {}
350 } 365 }
@@ -416,17 +431,11 @@ pub trait HasFormatSpecifier: AstToken {
416 } 431 }
417 } 432 }
418 433
419 let mut cloned = chars.clone().take(2); 434 if let Some((_, Ok('}'))) = chars.peek() {
420 let first = cloned.next().and_then(|next| next.1.as_ref().ok()).copied(); 435 skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback);
421 let second = cloned.next().and_then(|next| next.1.as_ref().ok()).copied(); 436 } else {
422 if first != Some('}') {
423 continue;
424 }
425 if second == Some('}') {
426 // Escaped format end specifier, `}}`
427 continue; 437 continue;
428 } 438 }
429 skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback);
430 } 439 }
431 _ => { 440 _ => {
432 while let Some((_, Ok(next_char))) = chars.peek() { 441 while let Some((_, Ok(next_char))) = chars.peek() {