mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Don't mess with cursor position when adding hashes
This commit is contained in:
parent
1fb92d791e
commit
68706b59c9
4 changed files with 34 additions and 16 deletions
|
@ -1,5 +1,7 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
ast::{self, HasStringValue},
|
ast::{self, HasQuotes, HasStringValue},
|
||||||
AstToken,
|
AstToken,
|
||||||
SyntaxKind::{RAW_STRING, STRING},
|
SyntaxKind::{RAW_STRING, STRING},
|
||||||
TextSize,
|
TextSize,
|
||||||
|
@ -32,14 +34,17 @@ pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext) -> Option<
|
||||||
target,
|
target,
|
||||||
|edit| {
|
|edit| {
|
||||||
let max_hash_streak = count_hashes(&value);
|
let max_hash_streak = count_hashes(&value);
|
||||||
let mut hashes = String::with_capacity(max_hash_streak + 1);
|
let hashes = "#".repeat(max_hash_streak + 1);
|
||||||
for _ in 0..hashes.capacity() {
|
if matches!(value, Cow::Borrowed(_)) {
|
||||||
hashes.push('#');
|
// 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(
|
edit.replace(
|
||||||
token.syntax().text_range(),
|
token.syntax().text_range(),
|
||||||
format!("r{}\"{}\"{}", hashes, value, hashes),
|
format!("r{}\"{}\"{}", hashes, value, hashes),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -70,6 +75,14 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext) -> Optio
|
||||||
|edit| {
|
|edit| {
|
||||||
// parse inside string to escape `"`
|
// parse inside string to escape `"`
|
||||||
let escaped = value.escape_default().to_string();
|
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));
|
edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped));
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -272,7 +272,7 @@ fn format_args_expand(
|
||||||
fn unquote_str(lit: &tt::Literal) -> Option<String> {
|
fn unquote_str(lit: &tt::Literal) -> Option<String> {
|
||||||
let lit = ast::make::tokens::literal(&lit.to_string());
|
let lit = ast::make::tokens::literal(&lit.to_string());
|
||||||
let token = ast::String::cast(lit)?;
|
let token = ast::String::cast(lit)?;
|
||||||
token.value()
|
token.value().map(|it| it.into_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn concat_expand(
|
fn concat_expand(
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub(super) fn highlight_injection(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let value = literal.value()?;
|
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() {
|
if let Some(range) = literal.open_quote_text_range() {
|
||||||
acc.add(HighlightedRange {
|
acc.add(HighlightedRange {
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
//! There are many AstNodes, but only a few tokens, so we hand-write them here.
|
//! 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::{
|
use crate::{
|
||||||
ast::{AstToken, Comment, RawString, String, Whitespace},
|
ast::{AstToken, Comment, RawString, String, Whitespace},
|
||||||
|
@ -138,11 +141,11 @@ impl HasQuotes for String {}
|
||||||
impl HasQuotes for RawString {}
|
impl HasQuotes for RawString {}
|
||||||
|
|
||||||
pub trait HasStringValue: HasQuotes {
|
pub trait HasStringValue: HasQuotes {
|
||||||
fn value(&self) -> Option<std::string::String>;
|
fn value(&self) -> Option<Cow<'_, str>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HasStringValue for String {
|
impl HasStringValue for String {
|
||||||
fn value(&self) -> Option<std::string::String> {
|
fn value(&self) -> Option<Cow<'_, str>> {
|
||||||
let text = self.text().as_str();
|
let text = self.text().as_str();
|
||||||
let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
|
let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
|
||||||
|
|
||||||
|
@ -156,15 +159,17 @@ impl HasStringValue for String {
|
||||||
if has_error {
|
if has_error {
|
||||||
return None;
|
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 {
|
impl HasStringValue for RawString {
|
||||||
fn value(&self) -> Option<std::string::String> {
|
fn value(&self) -> Option<Cow<'_, str>> {
|
||||||
let text = self.text().as_str();
|
let text = self.text().as_str();
|
||||||
let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
|
let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
|
||||||
Some(text.to_string())
|
Some(Cow::Borrowed(text))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue