From 68706b59c9177db2a6dd276e1ce599d8fe5942c1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 9 Jul 2020 19:21:41 +0200 Subject: Don't mess with cursor position when adding hashes --- crates/ra_assists/src/handlers/raw_string.rs | 31 +++++++++++++++------- crates/ra_hir_expand/src/builtin_macro.rs | 2 +- crates/ra_ide/src/syntax_highlighting/injection.rs | 2 +- crates/ra_syntax/src/ast/tokens.rs | 17 +++++++----- 4 files changed, 35 insertions(+), 17 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/handlers/raw_string.rs b/crates/ra_assists/src/handlers/raw_string.rs index 96679e160..6d77dff13 100644 --- a/crates/ra_assists/src/handlers/raw_string.rs +++ b/crates/ra_assists/src/handlers/raw_string.rs @@ -1,5 +1,7 @@ +use std::borrow::Cow; + use ra_syntax::{ - ast::{self, HasStringValue}, + ast::{self, HasQuotes, HasStringValue}, AstToken, SyntaxKind::{RAW_STRING, STRING}, TextSize, @@ -32,14 +34,17 @@ pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext) -> Option< target, |edit| { let max_hash_streak = count_hashes(&value); - let mut hashes = String::with_capacity(max_hash_streak + 1); - for _ in 0..hashes.capacity() { - hashes.push('#'); - } - edit.replace( - token.syntax().text_range(), - format!("r{}\"{}\"{}", hashes, value, hashes), - ); + let hashes = "#".repeat(max_hash_streak + 1); + if matches!(value, Cow::Borrowed(_)) { + // Avoid replacing the whole string to better position the cursor. + edit.insert(token.syntax().text_range().start(), format!("r{}", hashes)); + edit.insert(token.syntax().text_range().end(), format!("{}", hashes)); + } else { + edit.replace( + token.syntax().text_range(), + format!("r{}\"{}\"{}", hashes, value, hashes), + ); + } }, ) } @@ -70,6 +75,14 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext) -> Optio |edit| { // parse inside string to escape `"` let escaped = value.escape_default().to_string(); + if let Some(offsets) = token.quote_offsets() { + if token.text()[offsets.contents - token.syntax().text_range().start()] == escaped { + edit.replace(offsets.quotes.0, "\""); + edit.replace(offsets.quotes.1, "\""); + return; + } + } + edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped)); }, ) diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index 626f9efd0..9f50569dc 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs @@ -272,7 +272,7 @@ fn format_args_expand( fn unquote_str(lit: &tt::Literal) -> Option { let lit = ast::make::tokens::literal(&lit.to_string()); let token = ast::String::cast(lit)?; - token.value() + token.value().map(|it| it.into_owned()) } fn concat_expand( diff --git a/crates/ra_ide/src/syntax_highlighting/injection.rs b/crates/ra_ide/src/syntax_highlighting/injection.rs index 181c21256..8665b480f 100644 --- a/crates/ra_ide/src/syntax_highlighting/injection.rs +++ b/crates/ra_ide/src/syntax_highlighting/injection.rs @@ -25,7 +25,7 @@ pub(super) fn highlight_injection( return None; } let value = literal.value()?; - let (analysis, tmp_file_id) = Analysis::from_single_file(value); + let (analysis, tmp_file_id) = Analysis::from_single_file(value.into_owned()); if let Some(range) = literal.open_quote_text_range() { acc.add(HighlightedRange { diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs index 2e72d4927..045f69133 100644 --- a/crates/ra_syntax/src/ast/tokens.rs +++ b/crates/ra_syntax/src/ast/tokens.rs @@ -1,6 +1,9 @@ //! There are many AstNodes, but only a few tokens, so we hand-write them here. -use std::convert::{TryFrom, TryInto}; +use std::{ + borrow::Cow, + convert::{TryFrom, TryInto}, +}; use crate::{ ast::{AstToken, Comment, RawString, String, Whitespace}, @@ -138,11 +141,11 @@ impl HasQuotes for String {} impl HasQuotes for RawString {} pub trait HasStringValue: HasQuotes { - fn value(&self) -> Option; + fn value(&self) -> Option>; } impl HasStringValue for String { - fn value(&self) -> Option { + fn value(&self) -> Option> { let text = self.text().as_str(); let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; @@ -156,15 +159,17 @@ impl HasStringValue for String { if has_error { return None; } - Some(buf) + // FIXME: don't actually allocate for borrowed case + let res = if buf == text { Cow::Borrowed(text) } else { Cow::Owned(buf) }; + Some(res) } } impl HasStringValue for RawString { - fn value(&self) -> Option { + fn value(&self) -> Option> { let text = self.text().as_str(); let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; - Some(text.to_string()) + Some(Cow::Borrowed(text)) } } -- cgit v1.2.3