Skip to content

Commit 4e4e8b5

Browse files
committed
Migrate raw_string assist to use SyntaxEditor
1 parent 606a145 commit 4e4e8b5

File tree

1 file changed

+45
-40
lines changed

1 file changed

+45
-40
lines changed

crates/ide-assists/src/handlers/raw_string.rs

Lines changed: 45 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
use std::borrow::Cow;
2-
3-
use syntax::{AstToken, TextRange, TextSize, ast, ast::IsString};
1+
use ide_db::source_change::SourceChangeBuilder;
2+
use syntax::{
3+
AstToken,
4+
ast::{self, IsString, make::tokens::literal},
5+
};
46

57
use crate::{
68
AssistContext, AssistId, Assists,
@@ -35,17 +37,10 @@ pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
3537
target,
3638
|edit| {
3739
let hashes = "#".repeat(required_hashes(&value).max(1));
38-
let range = token.syntax().text_range();
3940
let raw_prefix = token.raw_prefix();
4041
let suffix = string_suffix(token.text()).unwrap_or_default();
41-
let range = TextRange::new(range.start(), range.end() - TextSize::of(suffix));
42-
if matches!(value, Cow::Borrowed(_)) {
43-
// Avoid replacing the whole string to better position the cursor.
44-
edit.insert(range.start(), format!("{raw_prefix}{hashes}"));
45-
edit.insert(range.end(), hashes);
46-
} else {
47-
edit.replace(range, format!("{raw_prefix}{hashes}\"{value}\"{hashes}"));
48-
}
42+
let new_str = format!("{raw_prefix}{hashes}\"{value}\"{hashes}{suffix}");
43+
replace_literal(&token, &new_str, edit, ctx);
4944
},
5045
)
5146
}
@@ -81,21 +76,8 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
8176
let escaped = value.escape_default().to_string();
8277
let suffix = string_suffix(token.text()).unwrap_or_default();
8378
let prefix = string_prefix(token.text()).map_or("", |s| s.trim_end_matches('r'));
84-
if let Some(offsets) = token.quote_offsets()
85-
&& token.text()[offsets.contents - token.syntax().text_range().start()] == escaped
86-
{
87-
let start_quote = offsets.quotes.0;
88-
let start_quote =
89-
TextRange::new(start_quote.start() + TextSize::of(prefix), start_quote.end());
90-
let end_quote = offsets.quotes.1;
91-
let end_quote =
92-
TextRange::new(end_quote.start(), end_quote.end() - TextSize::of(suffix));
93-
edit.replace(end_quote, "\"");
94-
edit.replace(start_quote, "\"");
95-
return;
96-
}
97-
98-
edit.replace(token.syntax().text_range(), format!("{prefix}\"{escaped}\"{suffix}"));
79+
let new_str = format!("{prefix}\"{escaped}\"{suffix}");
80+
replace_literal(&token, &new_str, edit, ctx);
9981
},
10082
)
10183
}
@@ -120,12 +102,14 @@ pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()>
120102
if !token.is_raw() {
121103
return None;
122104
}
123-
let text_range = token.syntax().text_range();
124-
let target = text_range;
105+
let target = token.syntax().text_range();
125106
acc.add(AssistId::refactor("add_hash"), "Add #", target, |edit| {
126-
let suffix = string_suffix(token.text()).unwrap_or_default();
127-
edit.insert(text_range.start() + TextSize::of(token.raw_prefix()), "#");
128-
edit.insert(text_range.end() - TextSize::of(suffix), "#");
107+
let str = token.text();
108+
let suffix = string_suffix(str).unwrap_or_default();
109+
let raw_prefix = token.raw_prefix();
110+
let wrap_range = raw_prefix.len()..str.len() - suffix.len();
111+
let new_str = [raw_prefix, "#", &str[wrap_range], "#", suffix].concat();
112+
replace_literal(&token, &new_str, edit, ctx);
129113
})
130114
}
131115

@@ -165,17 +149,38 @@ pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
165149

166150
acc.add(AssistId::refactor_rewrite("remove_hash"), "Remove #", text_range, |edit| {
167151
let suffix = string_suffix(text).unwrap_or_default();
168-
edit.delete(TextRange::at(
169-
text_range.start() + TextSize::of(token.raw_prefix()),
170-
TextSize::of('#'),
171-
));
172-
edit.delete(
173-
TextRange::new(text_range.end() - TextSize::of('#'), text_range.end())
174-
- TextSize::of(suffix),
175-
);
152+
let prefix = token.raw_prefix();
153+
let wrap_range = prefix.len() + 1..text.len() - suffix.len() - 1;
154+
let new_str = [prefix, &text[wrap_range], suffix].concat();
155+
replace_literal(&token, &new_str, edit, ctx);
176156
})
177157
}
178158

159+
fn replace_literal(
160+
token: &impl AstToken,
161+
new: &str,
162+
builder: &mut SourceChangeBuilder,
163+
ctx: &AssistContext<'_>,
164+
) {
165+
let token = token.syntax();
166+
let node = token.parent().expect("no parent token");
167+
let mut edit = builder.make_editor(&node);
168+
let new_literal = literal(new);
169+
170+
edit.replace(token, mut_token(new_literal));
171+
172+
builder.add_file_edits(ctx.vfs_file_id(), edit);
173+
}
174+
175+
fn mut_token(token: syntax::SyntaxToken) -> syntax::SyntaxToken {
176+
let node = token.parent().expect("no parent token");
177+
node.clone_for_update()
178+
.children_with_tokens()
179+
.filter_map(|it| it.into_token())
180+
.find(|it| it.text_range() == token.text_range() && it.text() == token.text())
181+
.unwrap()
182+
}
183+
179184
#[cfg(test)]
180185
mod tests {
181186
use super::*;

0 commit comments

Comments
 (0)