@@ -4,7 +4,7 @@ use syntax::{
4
4
algo,
5
5
ast:: { self , make, AstNode } ,
6
6
ted:: { self , Position } ,
7
- AstToken , NodeOrToken , SyntaxToken , TextRange , T ,
7
+ NodeOrToken , SyntaxToken , TextRange , T ,
8
8
} ;
9
9
10
10
use crate :: { AssistContext , AssistId , AssistKind , Assists } ;
@@ -55,39 +55,46 @@ fn attempt_get_derive(attr: ast::Attr, ident: SyntaxToken) -> WrapUnwrapOption {
55
55
syntax:: Direction :: Next ,
56
56
) ?;
57
57
if ( prev. kind ( ) == T ! [ , ] || prev. kind ( ) == T ! [ '(' ] )
58
- && ( following. kind ( ) == T ! [ , ] || following. kind ( ) == T ! [ '( ' ] )
58
+ && ( following. kind ( ) == T ! [ , ] || following. kind ( ) == T ! [ ') ' ] )
59
59
{
60
60
// This would be a single ident such as Debug. As no path is present
61
61
if following. kind ( ) == T ! [ , ] {
62
62
derive = derive. cover ( following. text_range ( ) ) ;
63
+ } else if following. kind ( ) == T ! [ ')' ] && prev. kind ( ) == T ! [ , ] {
64
+ derive = derive. cover ( prev. text_range ( ) ) ;
63
65
}
64
66
65
67
Some ( WrapUnwrapOption :: WrapDerive { derive, attr : attr. clone ( ) } )
66
68
} else {
69
+ let mut consumed_comma = false ;
67
70
// Collect the path
68
-
69
71
while let Some ( prev_token) = algo:: skip_trivia_token ( prev, syntax:: Direction :: Prev )
70
72
{
71
73
let kind = prev_token. kind ( ) ;
72
- if kind == T ! [ , ] || kind == T ! [ '(' ] {
74
+ if kind == T ! [ , ] {
75
+ consumed_comma = true ;
76
+ derive = derive. cover ( prev_token. text_range ( ) ) ;
77
+ break ;
78
+ } else if kind == T ! [ '(' ] {
73
79
break ;
80
+ } else {
81
+ derive = derive. cover ( prev_token. text_range ( ) ) ;
74
82
}
75
- derive = derive. cover ( prev_token. text_range ( ) ) ;
76
83
prev = prev_token. prev_sibling_or_token ( ) ?. into_token ( ) ?;
77
84
}
78
85
while let Some ( next_token) =
79
86
algo:: skip_trivia_token ( following. clone ( ) , syntax:: Direction :: Next )
80
87
{
81
88
let kind = next_token. kind ( ) ;
82
- if kind != T ! [ ')' ] {
83
- // We also want to consume a following comma
84
- derive = derive. cover ( next_token. text_range ( ) ) ;
89
+ match kind {
90
+ T ! [ , ] if !consumed_comma => {
91
+ derive = derive. cover ( next_token. text_range ( ) ) ;
92
+ break ;
93
+ }
94
+ T ! [ ')' ] | T ! [ , ] => break ,
95
+ _ => derive = derive. cover ( next_token. text_range ( ) ) ,
85
96
}
86
97
following = next_token. next_sibling_or_token ( ) ?. into_token ( ) ?;
87
-
88
- if kind == T ! [ , ] || kind == T ! [ ')' ] {
89
- break ;
90
- }
91
98
}
92
99
Some ( WrapUnwrapOption :: WrapDerive { derive, attr : attr. clone ( ) } )
93
100
}
@@ -103,14 +110,15 @@ fn attempt_get_derive(attr: ast::Attr, ident: SyntaxToken) -> WrapUnwrapOption {
103
110
}
104
111
pub ( crate ) fn wrap_unwrap_cfg_attr ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
105
112
let option = if ctx. has_empty_selection ( ) {
106
- let ident = ctx. find_token_at_offset :: < ast :: Ident > ( ) . map ( |v| v . syntax ( ) . clone ( ) ) ;
113
+ let ident = ctx. find_token_syntax_at_offset ( T ! [ ident ] ) ;
107
114
let attr = ctx. find_node_at_offset :: < ast:: Attr > ( ) ;
108
115
match ( attr, ident) {
109
116
( Some ( attr) , Some ( ident) )
110
117
if attr. simple_name ( ) . map ( |v| v. eq ( "derive" ) ) . unwrap_or_default ( ) =>
111
118
{
112
119
Some ( attempt_get_derive ( attr. clone ( ) , ident) )
113
120
}
121
+
114
122
( Some ( attr) , _) => Some ( WrapUnwrapOption :: WrapAttr ( attr) ) ,
115
123
_ => None ,
116
124
}
@@ -156,7 +164,7 @@ fn wrap_derive(
156
164
}
157
165
158
166
if derive_element. contains_range ( token. text_range ( ) ) {
159
- if token. kind ( ) != T ! [ , ] {
167
+ if token. kind ( ) != T ! [ , ] && token . kind ( ) != syntax :: SyntaxKind :: WHITESPACE {
160
168
path_text. push_str ( token. text ( ) ) ;
161
169
cfg_derive_tokens. push ( NodeOrToken :: Token ( token) ) ;
162
170
}
@@ -527,7 +535,42 @@ mod tests {
527
535
}
528
536
"# ,
529
537
r#"
530
- #[derive(Clone, Copy)]
538
+ #[derive(Clone, Copy)]
539
+ #[cfg_attr($0, derive(std::fmt::Debug))]
540
+ pub struct Test {
541
+ test: u32,
542
+ }
543
+ "# ,
544
+ ) ;
545
+ }
546
+ #[ test]
547
+ fn test_derive_wrap_at_end ( ) {
548
+ check_assist (
549
+ wrap_unwrap_cfg_attr,
550
+ r#"
551
+ #[derive(std::fmt::Debug, Clone, Cop$0y)]
552
+ pub struct Test {
553
+ test: u32,
554
+ }
555
+ "# ,
556
+ r#"
557
+ #[derive(std::fmt::Debug, Clone)]
558
+ #[cfg_attr($0, derive(Copy))]
559
+ pub struct Test {
560
+ test: u32,
561
+ }
562
+ "# ,
563
+ ) ;
564
+ check_assist (
565
+ wrap_unwrap_cfg_attr,
566
+ r#"
567
+ #[derive(Clone, Copy, std::fmt::D$0ebug)]
568
+ pub struct Test {
569
+ test: u32,
570
+ }
571
+ "# ,
572
+ r#"
573
+ #[derive(Clone, Copy)]
531
574
#[cfg_attr($0, derive(std::fmt::Debug))]
532
575
pub struct Test {
533
576
test: u32,
0 commit comments