mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-12-23 08:48:08 +00:00
Fix not applicable c-str and byte-str for raw_string
Example
---
Assist: `make_raw_string`
```rust
fn f() {
let s = $0b"random\nstring";
}
```
->
```rust
fn f() {
let s = br#"random
string"#;
}
```
---
Assist: `make_raw_string`
```rust
fn f() {
let s = $0c"random\nstring";
}
```
->
```rust
fn f() {
let s = cr#"random
string"#;
}
```
---
Assist: `add_hash`
```rust
fn f() {
let s = $0cr"random string";
}
```
->
```rust
fn f() {
let s = cr#"random string"#;
}
```
---
Assist: `remove_hash`
```rust
fn f() {
let s = $0cr#"random string"#;
}
```
->
```rust
fn f() {
let s = cr"random string";
}
```
---
Assist: `make_usual_string`
```rust
fn f() {
let s = $0cr#"random string"#;
}
```
->
```rust
fn f() {
let s = c"random string";
}
```
This commit is contained in:
parent
90d2e1ce4d
commit
e4cceca607
4 changed files with 202 additions and 27 deletions
|
|
@ -29,7 +29,9 @@ pub use self::{
|
|||
SlicePatComponents, StructKind, TypeBoundKind, TypeOrConstParam, VisibilityKind,
|
||||
},
|
||||
operators::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp},
|
||||
token_ext::{CommentKind, CommentPlacement, CommentShape, IsString, QuoteOffsets, Radix},
|
||||
token_ext::{
|
||||
AnyString, CommentKind, CommentPlacement, CommentShape, IsString, QuoteOffsets, Radix,
|
||||
},
|
||||
traits::{
|
||||
AttrDocCommentIter, DocCommentIter, HasArgList, HasAttrs, HasDocComments, HasGenericArgs,
|
||||
HasGenericParams, HasLoopBody, HasModuleItem, HasName, HasTypeBounds, HasVisibility,
|
||||
|
|
|
|||
|
|
@ -151,10 +151,10 @@ impl QuoteOffsets {
|
|||
}
|
||||
|
||||
pub trait IsString: AstToken {
|
||||
const RAW_PREFIX: &'static str;
|
||||
fn unescape(s: &str, callback: impl FnMut(Range<usize>, Result<char, EscapeError>));
|
||||
fn raw_prefix(&self) -> &'static str;
|
||||
fn unescape(&self, s: &str, callback: impl FnMut(Range<usize>, Result<char, EscapeError>));
|
||||
fn is_raw(&self) -> bool {
|
||||
self.text().starts_with(Self::RAW_PREFIX)
|
||||
self.text().starts_with(self.raw_prefix())
|
||||
}
|
||||
fn quote_offsets(&self) -> Option<QuoteOffsets> {
|
||||
let text = self.text();
|
||||
|
|
@ -187,7 +187,7 @@ pub trait IsString: AstToken {
|
|||
let text = &self.text()[text_range_no_quotes - start];
|
||||
let offset = text_range_no_quotes.start() - start;
|
||||
|
||||
Self::unescape(text, &mut |range: Range<usize>, unescaped_char| {
|
||||
self.unescape(text, &mut |range: Range<usize>, unescaped_char| {
|
||||
if let Some((s, e)) = range.start.try_into().ok().zip(range.end.try_into().ok()) {
|
||||
cb(TextRange::new(s, e) + offset, unescaped_char);
|
||||
}
|
||||
|
|
@ -204,8 +204,10 @@ pub trait IsString: AstToken {
|
|||
}
|
||||
|
||||
impl IsString for ast::String {
|
||||
const RAW_PREFIX: &'static str = "r";
|
||||
fn unescape(s: &str, cb: impl FnMut(Range<usize>, Result<char, EscapeError>)) {
|
||||
fn raw_prefix(&self) -> &'static str {
|
||||
"r"
|
||||
}
|
||||
fn unescape(&self, s: &str, cb: impl FnMut(Range<usize>, Result<char, EscapeError>)) {
|
||||
unescape_str(s, cb)
|
||||
}
|
||||
}
|
||||
|
|
@ -246,8 +248,10 @@ impl ast::String {
|
|||
}
|
||||
|
||||
impl IsString for ast::ByteString {
|
||||
const RAW_PREFIX: &'static str = "br";
|
||||
fn unescape(s: &str, mut callback: impl FnMut(Range<usize>, Result<char, EscapeError>)) {
|
||||
fn raw_prefix(&self) -> &'static str {
|
||||
"br"
|
||||
}
|
||||
fn unescape(&self, s: &str, mut callback: impl FnMut(Range<usize>, Result<char, EscapeError>)) {
|
||||
unescape_byte_str(s, |range, res| callback(range, res.map(char::from)))
|
||||
}
|
||||
}
|
||||
|
|
@ -288,10 +292,12 @@ impl ast::ByteString {
|
|||
}
|
||||
|
||||
impl IsString for ast::CString {
|
||||
const RAW_PREFIX: &'static str = "cr";
|
||||
fn raw_prefix(&self) -> &'static str {
|
||||
"cr"
|
||||
}
|
||||
// NOTE: This method should only be used for highlighting ranges. The unescaped
|
||||
// char/byte is not used. For simplicity, we return an arbitrary placeholder char.
|
||||
fn unescape(s: &str, mut callback: impl FnMut(Range<usize>, Result<char, EscapeError>)) {
|
||||
fn unescape(&self, s: &str, mut callback: impl FnMut(Range<usize>, Result<char, EscapeError>)) {
|
||||
unescape_c_str(s, |range, _res| callback(range, Ok('_')))
|
||||
}
|
||||
}
|
||||
|
|
@ -465,6 +471,74 @@ impl ast::Byte {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum AnyString {
|
||||
ByteString(ast::ByteString),
|
||||
CString(ast::CString),
|
||||
String(ast::String),
|
||||
}
|
||||
|
||||
impl AnyString {
|
||||
pub fn value(&self) -> Result<Cow<'_, str>, EscapeError> {
|
||||
fn from_utf8(s: Cow<'_, [u8]>) -> Result<Cow<'_, str>, EscapeError> {
|
||||
match s {
|
||||
Cow::Borrowed(s) => str::from_utf8(s)
|
||||
.map_err(|_| EscapeError::NonAsciiCharInByte)
|
||||
.map(Cow::Borrowed),
|
||||
Cow::Owned(s) => String::from_utf8(s)
|
||||
.map_err(|_| EscapeError::NonAsciiCharInByte)
|
||||
.map(Cow::Owned),
|
||||
}
|
||||
}
|
||||
|
||||
match self {
|
||||
AnyString::String(s) => s.value(),
|
||||
AnyString::ByteString(s) => s.value().and_then(from_utf8),
|
||||
AnyString::CString(s) => s.value().and_then(from_utf8),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::AstToken for AnyString {
|
||||
fn can_cast(kind: crate::SyntaxKind) -> bool {
|
||||
ast::String::can_cast(kind)
|
||||
|| ast::ByteString::can_cast(kind)
|
||||
|| ast::CString::can_cast(kind)
|
||||
}
|
||||
|
||||
fn cast(syntax: crate::SyntaxToken) -> Option<Self> {
|
||||
ast::String::cast(syntax.clone())
|
||||
.map(Self::String)
|
||||
.or_else(|| ast::ByteString::cast(syntax.clone()).map(Self::ByteString))
|
||||
.or_else(|| ast::CString::cast(syntax).map(Self::CString))
|
||||
}
|
||||
|
||||
fn syntax(&self) -> &crate::SyntaxToken {
|
||||
match self {
|
||||
Self::ByteString(it) => it.syntax(),
|
||||
Self::CString(it) => it.syntax(),
|
||||
Self::String(it) => it.syntax(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsString for AnyString {
|
||||
fn raw_prefix(&self) -> &'static str {
|
||||
match self {
|
||||
AnyString::ByteString(s) => s.raw_prefix(),
|
||||
AnyString::CString(s) => s.raw_prefix(),
|
||||
AnyString::String(s) => s.raw_prefix(),
|
||||
}
|
||||
}
|
||||
|
||||
fn unescape(&self, s: &str, callback: impl FnMut(Range<usize>, Result<char, EscapeError>)) {
|
||||
match self {
|
||||
AnyString::ByteString(it) => it.unescape(s, callback),
|
||||
AnyString::CString(it) => it.unescape(s, callback),
|
||||
AnyString::String(it) => it.unescape(s, callback),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rustc_apfloat::ieee::Quad as f128;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue