1717package com .goide .formatter ;
1818
1919import com .goide .GoLanguage ;
20- import com .goide .GoParserDefinition ;
2120import com .goide .psi .GoStatement ;
21+ import com .goide .psi .GoType ;
2222import com .intellij .formatting .*;
23+ import com .intellij .formatting .alignment .AlignmentStrategy ;
2324import com .intellij .lang .ASTNode ;
25+ import com .intellij .openapi .util .Key ;
2426import com .intellij .openapi .util .TextRange ;
27+ import com .intellij .openapi .util .UserDataHolderBase ;
2528import com .intellij .psi .PsiElement ;
2629import com .intellij .psi .PsiFile ;
2730import com .intellij .psi .TokenType ;
2831import com .intellij .psi .codeStyle .CodeStyleSettings ;
32+ import com .intellij .psi .formatter .FormatterUtil ;
2933import com .intellij .psi .tree .IElementType ;
3034import com .intellij .psi .tree .TokenSet ;
3135import com .intellij .util .containers .ContainerUtil ;
3539import java .util .Collections ;
3640import java .util .List ;
3741
42+ import static com .goide .GoParserDefinition .LINE_COMMENT ;
43+ import static com .goide .GoParserDefinition .MULTILINE_COMMENT ;
3844import static com .goide .GoTypes .*;
3945
4046public class GoFormattingModelBuilder implements FormattingModelBuilder {
@@ -104,10 +110,15 @@ private static SpacingBuilder createSpacingBuilder(@NotNull CodeStyleSettings se
104110 .beforeInside (LBRACE , LITERAL_VALUE ).none ()
105111 .afterInside (BIT_AND , UNARY_EXPR ).none ()
106112 .beforeInside (TYPE , VAR_SPEC ).spaces (1 )
107- .after (GoParserDefinition . LINE_COMMENT ).lineBreakInCodeIf (true )
108- .after (GoParserDefinition . MULTILINE_COMMENT ).lineBreakInCodeIf (true )
113+ .after (LINE_COMMENT ).lineBreakInCodeIf (true )
114+ .after (MULTILINE_COMMENT ).lineBreakInCodeIf (true )
109115 .between (COMM_CASE , COLON ).none ()
110116 .afterInside (COLON , COMM_CLAUSE ).lineBreakInCode ()
117+ .betweenInside (FIELD_DECLARATION , LINE_COMMENT , STRUCT_TYPE ).spaces (1 )
118+ .betweenInside (FIELD_DECLARATION , MULTILINE_COMMENT , STRUCT_TYPE ).spaces (1 )
119+ .betweenInside (LBRACE , RBRACE , INTERFACE_TYPE ).none ()
120+ .betweenInside (LBRACE , RBRACE , STRUCT_TYPE ).none ()
121+ .betweenInside (LBRACK , RBRACK , ARRAY_OR_SLICE_TYPE ).none ()
111122 ;
112123 }
113124
@@ -117,7 +128,7 @@ public TextRange getRangeAffectingIndent(PsiFile file, int offset, ASTNode eleme
117128 return null ;
118129 }
119130
120- public static class GoFormattingBlock implements ASTBlock {
131+ public static class GoFormattingBlock extends UserDataHolderBase implements ASTBlock {
121132 public static final TokenSet BLOCKS_TOKEN_SET = TokenSet .create (
122133 BLOCK ,
123134 STRUCT_TYPE ,
@@ -136,6 +147,7 @@ public static class GoFormattingBlock implements ASTBlock {
136147 LPAREN ,
137148 RPAREN
138149 );
150+ public static final Key <Alignment > TYPE_ALIGNMENT_INSIDE_STRUCT = Key .create ("TYPE_ALIGNMENT_INSIDE_STRUCT" );
139151
140152 @ NotNull private final ASTNode myNode ;
141153 @ Nullable private final Alignment myAlignment ;
@@ -145,10 +157,10 @@ public static class GoFormattingBlock implements ASTBlock {
145157 @ NotNull private final SpacingBuilder mySpacingBuilder ;
146158 @ Nullable private List <Block > mySubBlocks ;
147159
148- public GoFormattingBlock (@ NotNull ASTNode node ,
149- @ Nullable Alignment alignment ,
150- @ Nullable Indent indent ,
151- @ Nullable Wrap wrap ,
160+ public GoFormattingBlock (@ NotNull ASTNode node ,
161+ @ Nullable Alignment alignment ,
162+ @ Nullable Indent indent ,
163+ @ Nullable Wrap wrap ,
152164 @ NotNull CodeStyleSettings settings ,
153165 @ NotNull SpacingBuilder spacingBuilder ) {
154166 myNode = node ;
@@ -200,20 +212,37 @@ public List<Block> getSubBlocks() {
200212
201213 @ NotNull
202214 private List <Block > buildSubBlocks () {
215+ AlignmentStrategy .AlignmentPerTypeStrategy strategy = null ;
216+ boolean isStruct = getNode ().getElementType () == STRUCT_TYPE ;
217+ Alignment forType = null ;
218+ if (isStruct ) {
219+ strategy = AlignmentStrategy .createAlignmentPerTypeStrategy (ContainerUtil .list (FIELD_DECLARATION , LINE_COMMENT ), STRUCT_TYPE , true );
220+ forType = Alignment .createAlignment (true );
221+ }
222+
203223 List <Block > blocks = ContainerUtil .newArrayList ();
204224 for (ASTNode child = myNode .getFirstChildNode (); child != null ; child = child .getTreeNext ()) {
205225 IElementType childType = child .getElementType ();
206226 if (child .getTextRange ().getLength () == 0 ) continue ;
207227 if (childType == TokenType .WHITE_SPACE ) continue ;
208- blocks .add (buildSubBlock (child ));
228+ IElementType substitutor = childType == MULTILINE_COMMENT ? LINE_COMMENT : childType ;
229+ Alignment alignment = strategy != null ? strategy .getAlignment (substitutor ) : null ;
230+ GoFormattingBlock e = buildSubBlock (child , alignment );
231+ if (isStruct ) {
232+ e .putUserDataIfAbsent (TYPE_ALIGNMENT_INSIDE_STRUCT , forType );
233+ }
234+ blocks .add (e );
209235 }
210236 return Collections .unmodifiableList (blocks );
211237 }
212238
213- @ Nullable
214- private Block buildSubBlock (@ NotNull ASTNode child ) {
239+ @ NotNull
240+ private GoFormattingBlock buildSubBlock (@ NotNull ASTNode child , @ Nullable Alignment alignment ) {
241+ if (child .getPsi () instanceof GoType && child .getTreeParent ().getElementType () == FIELD_DECLARATION ) {
242+ alignment = getUserData (TYPE_ALIGNMENT_INSIDE_STRUCT );
243+ }
215244 Indent indent = calcIndent (child );
216- return new GoFormattingBlock (child , null , indent , null , mySettings , mySpacingBuilder );
245+ return new GoFormattingBlock (child , alignment , indent , null , mySettings , mySpacingBuilder );
217246 }
218247
219248 @ NotNull
@@ -223,7 +252,7 @@ private Indent calcIndent(@NotNull ASTNode child) {
223252 if (type == SWITCH_START ) return Indent .getNoneIndent ();
224253 if (parentType == BLOCK && type == SELECT_STATEMENT ) return Indent .getNoneIndent ();
225254 if (parentType == SELECT_STATEMENT && type == RBRACE ) return Indent .getNormalIndent ();
226- if (parentType == ARGUMENT_LIST && type != LPAREN && type != RPAREN ) return Indent .getNormalIndent ();
255+ if (parentType == ARGUMENT_LIST && type != LPAREN && type != RPAREN ) return Indent .getNormalIndent ();
227256 if ((parentType == EXPR_CASE_CLAUSE || parentType == TYPE_CASE_CLAUSE ) && (type == CASE || type == DEFAULT )) return Indent .getNoneIndent ();
228257 if (BLOCKS_TOKEN_SET .contains (parentType )) return indentIfNotBrace (child );
229258 if (parentType == IMPORT_DECLARATION && type == IMPORT_SPEC ) return Indent .getNormalIndent ();
@@ -239,10 +268,27 @@ private static Indent indentIfNotBrace(@NotNull ASTNode child) {
239268 }
240269
241270 @ Override
242- public Spacing getSpacing (Block child1 , @ NotNull Block child2 ) {
271+ public Spacing getSpacing (@ Nullable Block child1 , @ NotNull Block child2 ) {
272+ if (child1 instanceof GoFormattingBlock && child2 instanceof GoFormattingBlock ) {
273+ ASTNode n1 = ((GoFormattingBlock )child1 ).getNode ();
274+ ASTNode n2 = ((GoFormattingBlock )child2 ).getNode ();
275+ if (n1 .getElementType () == FIELD_DEFINITION && n2 .getPsi () instanceof GoType ) return one ();
276+ if (n1 .getElementType () == INTERFACE && n2 .getElementType () == LBRACE ) {
277+ ASTNode next = FormatterUtil .getNextNonWhitespaceSibling (n2 );
278+ return next != null && next .getElementType () == RBRACE ? none () : one ();
279+ }
280+ }
243281 return mySpacingBuilder .getSpacing (this , child1 , child2 );
244282 }
245283
284+ private Spacing none () {
285+ return Spacing .createSpacing (0 , 0 , 0 , mySettings .KEEP_LINE_BREAKS , mySettings .KEEP_BLANK_LINES_IN_CODE );
286+ }
287+
288+ private Spacing one () {
289+ return Spacing .createSpacing (1 , 1 , 0 , mySettings .KEEP_LINE_BREAKS , mySettings .KEEP_BLANK_LINES_IN_CODE );
290+ }
291+
246292 @ NotNull
247293 @ Override
248294 public ChildAttributes getChildAttributes (int newChildIndex ) {
0 commit comments