Skip to content

Commit 2ffee5c

Browse files
committed
formatting for structures, fix #448
1 parent 2243f1d commit 2ffee5c

File tree

3 files changed

+93
-15
lines changed

3 files changed

+93
-15
lines changed

src/com/goide/formatter/GoFormattingModelBuilder.java

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,19 @@
1717
package com.goide.formatter;
1818

1919
import com.goide.GoLanguage;
20-
import com.goide.GoParserDefinition;
2120
import com.goide.psi.GoStatement;
21+
import com.goide.psi.GoType;
2222
import com.intellij.formatting.*;
23+
import com.intellij.formatting.alignment.AlignmentStrategy;
2324
import com.intellij.lang.ASTNode;
25+
import com.intellij.openapi.util.Key;
2426
import com.intellij.openapi.util.TextRange;
27+
import com.intellij.openapi.util.UserDataHolderBase;
2528
import com.intellij.psi.PsiElement;
2629
import com.intellij.psi.PsiFile;
2730
import com.intellij.psi.TokenType;
2831
import com.intellij.psi.codeStyle.CodeStyleSettings;
32+
import com.intellij.psi.formatter.FormatterUtil;
2933
import com.intellij.psi.tree.IElementType;
3034
import com.intellij.psi.tree.TokenSet;
3135
import com.intellij.util.containers.ContainerUtil;
@@ -35,6 +39,8 @@
3539
import java.util.Collections;
3640
import java.util.List;
3741

42+
import static com.goide.GoParserDefinition.LINE_COMMENT;
43+
import static com.goide.GoParserDefinition.MULTILINE_COMMENT;
3844
import static com.goide.GoTypes.*;
3945

4046
public 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) {

testData/formatting/simple-after.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,20 @@ func main() {
143143

144144
}
145145
}
146-
}
146+
}
147+
148+
149+
type T struct {
150+
name []string // name of the object
151+
value, a, b int // its value
152+
}
153+
154+
type x struct {
155+
x, y int // a
156+
u float32 // b
157+
_ float32 // c
158+
A1 *[]int // ca
159+
FFF func() // adsfasd
160+
X interface{} /* adsf*/
161+
X1 interface{} /* adsf*/
162+
}

testData/formatting/simple.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,19 @@ func main() {
139139
}
140140
}
141141
}
142+
143+
144+
type T struct {
145+
name [ ]string // name of the object
146+
value, a, b int // its value
147+
}
148+
149+
type x struct {
150+
x , y int // a
151+
u float32 // b
152+
_ float32 // c
153+
A1 * [ ]int // ca
154+
FFF func( ) // adsfasd
155+
X interface { } /* adsf*/
156+
X1 interface { } /* adsf*/
157+
}

0 commit comments

Comments
 (0)