1
- use crate :: dsl;
1
+ use crate :: dsl:: { self , SpaceLoc , SpaceValue , SpacingRule , SpacingDsl } ;
2
+ use crate :: fmt_model:: { FmtModel , SpaceBlock , BlockPosition } ;
3
+ use crate :: pattern:: PatternSet ;
4
+ use crate :: trav_util:: { has_newline} ;
5
+
2
6
use ra_syntax:: {
3
7
ast:: { self , AstNode , AstToken } ,
4
- Parse , SmolStr , SourceFile ,
5
- SyntaxElement , TextUnit ,
6
- SyntaxKind , SyntaxKind :: * ,
7
- SyntaxNode , SyntaxToken , T ,
8
- WalkEvent , TextRange ,
8
+ Parse , SmolStr , SourceFile , SyntaxElement , SyntaxKind ,
9
+ SyntaxKind :: * ,
10
+ SyntaxNode , SyntaxToken , TextRange , TextUnit , WalkEvent , T ,
9
11
} ;
10
12
use std:: collections:: HashMap ;
11
13
12
- #[ derive( Debug ) ]
13
-
14
- struct FmtTree {
15
- /// owned original root node
16
- original_node : SyntaxNode ,
17
- /// We store `SpaceBlock`s in array. With this setup, we can refer to a
18
- /// specific block by index, dodging many lifetime issues.
19
- blocks : Vec < SpaceBlock > ,
20
- /// Maps offset to an index of the block, for which the offset is the start
21
- /// offset.
22
- by_start_offset : HashMap < TextUnit , usize > ,
23
- /// Maps offset to an index of the block, for which the offset is the end
24
- /// offset.
25
- by_end_offset : HashMap < TextUnit , usize > ,
26
- // Arbitrary non-whitespace edits created by the last formatter phase.
27
- //fixes: Vec<AtomEdit>,
28
- }
29
-
30
- #[ derive( Debug ) ]
31
- pub ( super ) struct SpaceBlock {
32
- original : OriginalSpace ,
33
- /// Block's textual content, which is seen and modified by formatting rules.
34
- new_text : Option < SmolStr > ,
35
- /// If this block requires a newline to preserve semantics.
36
- ///
37
- /// True for blocks after comments. The engine takes care to never remove
38
- /// newline, even if some interaction of rules asks us to do so.
39
- semantic_newline : bool ,
40
- }
41
-
42
-
43
-
44
- #[ derive( Debug , Clone , Copy ) ]
45
- pub ( super ) enum BlockPosition {
46
- Before ,
47
- After ,
48
- }
49
-
50
- /// Original whitespace token, if any, that backs a `SpaceBlock.
51
- #[ derive( Debug ) ]
52
- pub ( super ) enum OriginalSpace {
53
- Some ( SyntaxToken ) ,
54
- None { offset : TextUnit } ,
55
- }
56
-
57
- impl OriginalSpace {
58
- fn text_range ( & self ) -> TextRange {
14
+ impl SpaceLoc {
15
+ fn is_before ( self ) -> bool {
59
16
match self {
60
- OriginalSpace :: Some ( token) => token. text_range ( ) ,
61
- OriginalSpace :: None { offset } => TextRange :: from_to ( * offset, * offset) ,
17
+ SpaceLoc :: Before | SpaceLoc :: Around => true ,
18
+ SpaceLoc :: After => false ,
19
+ }
20
+ }
21
+ fn is_after ( self ) -> bool {
22
+ match self {
23
+ SpaceLoc :: After | SpaceLoc :: Around => true ,
24
+ SpaceLoc :: Before => false ,
62
25
}
63
26
}
64
27
}
65
28
66
- impl SpaceBlock {
67
- fn new ( original : OriginalSpace ) -> SpaceBlock {
68
- let semantic_newline = match & original {
69
- OriginalSpace :: Some ( token) => {
70
- token. text ( ) . contains ( '\n' )
29
+ fn ensure_space ( element : & SyntaxElement , block : & mut SpaceBlock , value : SpaceValue ) {
30
+ match value {
31
+ SpaceValue :: Single => block. set_text ( " " ) ,
32
+ SpaceValue :: SingleOptionalNewline => {
33
+ if !block. has_newline ( ) {
34
+ block. set_text ( " " )
71
35
}
72
- OriginalSpace :: None { .. } => false ,
73
- } ;
74
- SpaceBlock { original, new_text : None , semantic_newline }
75
- }
76
- pub ( super ) fn set_line_break_preserving_existing_newlines ( & mut self ) {
77
- if self . has_newline ( ) {
78
- return ;
79
- }
80
- self . set_text ( "\n " ) ;
81
- }
82
- pub ( super ) fn set_text ( & mut self , text : & str ) {
83
- if self . semantic_newline && !text. contains ( '\n' ) {
84
- return ;
85
36
}
86
- match & self . original {
87
- OriginalSpace :: Some ( token) if token. text ( ) == text && self . new_text . is_none ( ) => return ,
88
- _ => self . new_text = Some ( text. into ( ) ) ,
37
+ SpaceValue :: Newline => block. set_text ( "\n " ) ,
38
+ SpaceValue :: None => block. set_text ( "" ) ,
39
+ SpaceValue :: NoneOptionalNewline => {
40
+ if !block. has_newline ( ) {
41
+ block. set_text ( "" )
42
+ }
89
43
}
90
- }
91
- pub ( super ) fn text ( & self ) -> & str {
92
- if let Some ( text) = self . new_text . as_ref ( ) {
93
- return text. as_str ( ) ;
44
+ SpaceValue :: SingleOrNewline => {
45
+ let parent_is_multiline = element. parent ( ) . map_or ( false , |it| has_newline ( & it) ) ;
46
+ if parent_is_multiline {
47
+ block. set_line_break_preserving_existing_newlines ( )
48
+ } else {
49
+ block. set_text ( " " )
50
+ }
94
51
}
95
- self . original_text ( )
96
- }
97
- pub ( crate ) fn original_text ( & self ) -> & str {
98
- match & self . original {
99
- OriginalSpace :: Some ( token) => token. text ( ) . as_str ( ) ,
100
- OriginalSpace :: None { .. } => "" ,
52
+ SpaceValue :: NoneOrNewline => {
53
+ let parent_is_multiline = element. parent ( ) . map_or ( false , |it| has_newline ( & it) ) ;
54
+ if parent_is_multiline {
55
+ block. set_line_break_preserving_existing_newlines ( )
56
+ } else {
57
+ block. set_text ( "" )
58
+ }
101
59
}
102
60
}
103
- pub ( super ) fn has_newline ( & self ) -> bool {
104
- self . text ( ) . contains ( '\n' )
105
- }
106
61
}
107
62
108
- impl FmtTree {
109
- pub ( super ) fn new ( original_node : SyntaxNode ) -> Self {
110
- Self {
111
- original_node,
112
- blocks : vec ! [ ] ,
113
- by_start_offset : HashMap :: default ( ) ,
114
- by_end_offset : HashMap :: default ( ) ,
63
+ impl SpacingRule {
64
+ pub ( super ) fn apply ( & self , ele : & SyntaxElement , model : & mut FmtModel ) {
65
+ if !self . pattern . matches ( ele) {
66
+ return ;
67
+ }
68
+ if self . space . loc . is_before ( ) {
69
+ let block = model. block_for ( ele, BlockPosition :: Before ) ;
70
+ ensure_space ( ele, block, self . space . value ) ;
71
+ }
72
+ if self . space . loc . is_after ( ) {
73
+ let block = model. block_for ( ele, BlockPosition :: After ) ;
74
+ ensure_space ( ele, block, self . space . value ) ;
115
75
}
116
76
}
117
77
}
@@ -126,11 +86,14 @@ fn walk(node: &SyntaxNode) -> impl Iterator<Item = SyntaxElement> {
126
86
} )
127
87
}
128
88
129
- fn format_pass ( space_rules : & dsl:: SpacingDsl , root : & SyntaxNode ) {
130
- let mut fmt_root = FmtTree :: new ( root. clone ( ) ) ;
89
+ pub fn format_pass ( space_rules : & SpacingDsl , root : & SyntaxNode ) {
90
+ let mut fmt_root = FmtModel :: new ( root. clone ( ) ) ;
91
+
92
+ let rules_set = PatternSet :: new ( space_rules. rules . iter ( ) ) ;
93
+
131
94
for node in walk ( root) {
132
- for rule in space_rules . matching ( node. clone ( ) ) {
133
- rule. apply ( & node, & mut fmt_root)
134
- }
95
+ for rule in rules_set . matching ( node. clone ( ) ) {
96
+ rule. apply ( & node, & mut fmt_root)
97
+ }
135
98
}
136
99
}
0 commit comments