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
57use 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) ]
180185mod tests {
181186 use super :: * ;
0 commit comments