8
8
import com .intellij .formatting .Spacing ;
9
9
import com .intellij .formatting .SpacingBuilder ;
10
10
import com .intellij .formatting .Wrap ;
11
+ import com .intellij .formatting .WrapType ;
11
12
import com .intellij .lang .ASTNode ;
12
13
import com .intellij .openapi .util .TextRange ;
13
14
import com .intellij .psi .TokenType ;
14
15
import com .intellij .psi .codeStyle .CodeStyleSettings ;
16
+ import com .intellij .psi .formatter .FormatterUtil ;
17
+ import com .intellij .psi .impl .source .tree .LeafPsiElement ;
18
+ import com .intellij .psi .impl .source .tree .TreeUtil ;
19
+ import com .neueda .jetbrains .plugin .graphdb .language .cypher .psi .CypherTypes ;
15
20
import org .jetbrains .annotations .NotNull ;
16
21
import org .jetbrains .annotations .Nullable ;
17
22
18
23
import java .util .List ;
24
+ import java .util .Objects ;
25
+ import java .util .function .Predicate ;
19
26
import java .util .stream .Stream ;
20
27
21
28
import static java .util .stream .Collectors .toList ;
@@ -35,14 +42,13 @@ public class CypherBlock implements ASTBlock {
35
42
@ NotNull CodeStyleSettings settings ,
36
43
@ Nullable Wrap wrap ,
37
44
@ Nullable Indent indent ,
38
- @ Nullable Alignment alignment ,
39
- SpacingBuilder spacingBuilder ) {
45
+ @ Nullable Alignment alignment ) {
40
46
this .node = node ;
41
47
this .codeStyleSettings = settings ;
42
48
this .wrap = wrap ;
43
49
this .indent = indent ;
44
50
this .alignment = alignment ;
45
- this .spacingBuilder = spacingBuilder ;
51
+ this .spacingBuilder = CypherFormattingModelBuilder . createSpacingBuilder ( settings ) ;
46
52
}
47
53
48
54
@ Override
@@ -60,16 +66,46 @@ public TextRange getTextRange() {
60
66
@ Override
61
67
public List <Block > getSubBlocks () {
62
68
if (subBlocks == null ) {
69
+ Predicate <ASTNode > isWhitespaceOrEmpty = CypherBlock ::isWhitespaceOrEmpty ;
63
70
subBlocks = Stream .of (node .getChildren (null ))
64
- .filter (node -> ! CypherBlock . isWhitespaceOrEmpty ( node ))
71
+ .filter (isWhitespaceOrEmpty . negate ( ))
65
72
.map (this ::makeSubBlock )
73
+ .filter (Objects ::nonNull )
66
74
.collect (toList ());
67
75
}
68
76
return subBlocks ;
69
77
}
70
78
71
79
private Block makeSubBlock (@ NotNull ASTNode node ) {
72
- return new CypherBlock (node , codeStyleSettings , null , Indent .getNoneIndent (), null , spacingBuilder );
80
+ Wrap wrap = null ;
81
+ Indent indent = Indent .getNoneIndent ();
82
+
83
+ if (isTopLevel (node )) {
84
+ wrap = Wrap .createWrap (WrapType .ALWAYS , true );
85
+ indent = Indent .getNoneIndent ();
86
+ }
87
+
88
+ if (node .getElementType () == CypherTypes .K_ON ) {
89
+ if (TreeUtil .findParent (node , CypherTypes .MERGE ) != null ) {
90
+ wrap = Wrap .createWrap (WrapType .ALWAYS , true );
91
+ indent = Indent .getNormalIndent (true );
92
+ }
93
+ }
94
+
95
+ if (isReturnBodyKeywords (node )) {
96
+ wrap = Wrap .createWrap (WrapType .ALWAYS , true );
97
+ indent = Indent .getNormalIndent (false );
98
+ }
99
+
100
+ if (isTopLevel (node )) {
101
+ String original = node .getPsi ().getText ();
102
+ String text = original .toUpperCase ();
103
+ if (!original .equals (text )) {
104
+ node .getPsi (LeafPsiElement .class ).rawReplaceWithText (text );
105
+ }
106
+ }
107
+
108
+ return new CypherBlock (node , codeStyleSettings , wrap , indent , null );
73
109
}
74
110
75
111
@ Nullable
@@ -93,13 +129,18 @@ public Alignment getAlignment() {
93
129
@ Nullable
94
130
@ Override
95
131
public Spacing getSpacing (@ Nullable Block child1 , @ NotNull Block child2 ) {
132
+ //todo Add more complex login on spacing, if needed
133
+
96
134
return spacingBuilder .getSpacing (this , child1 , child2 );
97
135
}
98
136
99
137
@ NotNull
100
138
@ Override
101
139
public ChildAttributes getChildAttributes (int newChildIndex ) {
102
- return new ChildAttributes (null , null );
140
+ Indent indent = Indent .getNoneIndent ();
141
+ //todo add child indentation rules
142
+
143
+ return new ChildAttributes (indent , null );
103
144
}
104
145
105
146
@ Override
@@ -115,4 +156,22 @@ public boolean isLeaf() {
115
156
private static boolean isWhitespaceOrEmpty (ASTNode node ) {
116
157
return node .getElementType () == TokenType .WHITE_SPACE || node .getTextLength () == 0 ;
117
158
}
159
+
160
+ private static boolean isTopLevel (ASTNode node ) {
161
+ return FormatterUtil .isOneOf (node ,
162
+ CypherTypes .CREATE ,
163
+ CypherTypes .MERGE ,
164
+ CypherTypes .MATCH ,
165
+ CypherTypes .WHERE ,
166
+ CypherTypes .WITH ,
167
+ CypherTypes .UNION ,
168
+ CypherTypes .RETURN );
169
+ }
170
+
171
+ private static boolean isReturnBodyKeywords (ASTNode node ) {
172
+ return FormatterUtil .isOneOf (node ,
173
+ CypherTypes .LIMIT ,
174
+ CypherTypes .SKIP ,
175
+ CypherTypes .ORDER );
176
+ }
118
177
}
0 commit comments