diff --git a/src/main/grammar/Aspect.flex b/src/main/grammar/Aspect.flex index 671249c9a3a6c97ba3d764f5297f2604aa92dc1d..80a77cd34584028eb9bd93b7d2c24d5c0eb8a491 100644 --- a/src/main/grammar/Aspect.flex +++ b/src/main/grammar/Aspect.flex @@ -33,7 +33,7 @@ import com.intellij.psi.TokenType; WhiteSpace = [ \t\n\r\f] // TODO what is /**/ in Java? Is this caputered here? -SingleLineComment = "//" [^\n\r]* (\n | \r | \r\n) +SingleLineComment = "//" [^\n\r]* FormalComment = "/**" [^*]* [*]+([^*/][^*]*[*]+)*[/] MultiLineComment = "/*" [^*]+ [*]+([^*/][^*]*[*]+)*[/] diff --git a/src/main/java/org/jastadd/tooling/aspect/AspectBlock.java b/src/main/java/org/jastadd/tooling/aspect/AspectBlock.java new file mode 100644 index 0000000000000000000000000000000000000000..f6c6d7b56a313e8ed01eda0314da647d8abf3788 --- /dev/null +++ b/src/main/java/org/jastadd/tooling/aspect/AspectBlock.java @@ -0,0 +1,129 @@ +package org.jastadd.tooling.aspect; + + +import com.intellij.formatting.*; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.psi.TokenType; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.formatter.common.AbstractBlock; +import com.intellij.psi.formatter.common.InjectedLanguageBlockBuilder; +import com.intellij.psi.formatter.java.LeafBlock; +import com.intellij.psi.tree.IElementType; +import org.jastadd.tooling.aspect.psi.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class AspectBlock extends AbstractBlock { + + private final SpacingBuilder spacingBuilder; + private final InjectedLanguageBlockBuilder myInjectedBlockBuilder; + + protected AspectBlock(@NotNull ASTNode node, @Nullable Wrap wrap, @Nullable Alignment alignment, + SpacingBuilder spacingBuilder) { + super(node, wrap, alignment); + this.spacingBuilder = spacingBuilder; + + myInjectedBlockBuilder = new JavaBlockInjectedBlockBuilder(); + } + + @Override + protected List<Block> buildChildren() { + List<Block> blocks = new ArrayList<>(); + if (myNode.getPsi() instanceof JastAddAspectAspectClassDeclaration) { + myInjectedBlockBuilder.addInjectedBlocks(blocks, myNode, Wrap.createWrap(WrapType.NONE, false), null, Indent.getIndent(Indent.Type.NONE, false, true)); + } else if (myNode.getPsi() instanceof JastAddAspectBlock) { + myInjectedBlockBuilder.addInjectedBlocks(blocks, myNode, Wrap.createWrap(WrapType.NONE, false), null, Indent.getIndent(Indent.Type.NONE, false, true)); + } else if (myNode.getPsi() instanceof JastAddAspectExpression) { + myInjectedBlockBuilder.addInjectedBlocks(blocks, myNode, Wrap.createWrap(WrapType.NONE, false), null, Indent.getIndent(Indent.Type.NONE, false, true)); + } else { + ASTNode child = myNode.getFirstChildNode(); + while (child != null) { + if (child.getElementType() != TokenType.WHITE_SPACE) { + Block block = new AspectBlock(child, Wrap.createWrap(WrapType.NONE, false), null, spacingBuilder); + blocks.add(block); + } + child = child.getTreeNext(); + } + } + return blocks; + } + + @Override + public Indent getIndent() { + if (myNode.getTreeParent() != null) { + PsiElement parentPsi = myNode.getTreeParent().getPsi(); + IElementType childType = myNode.getElementType(); + if (parentPsi instanceof JastAddAspectAspectBody && childType != AspectTypes.RBRACE) { + return Indent.getNormalIndent(); + } else if (parentPsi instanceof JastAddAspectAspectConstructorDeclaration && (myNode.getPsi() instanceof JastAddAspectExplicitConstructorInvocation || myNode.getPsi() instanceof JastAddAspectBlockStatement)) { + return Indent.getNormalIndent(); + } else if (parentPsi instanceof JastAddAspectCollectionAttribute && (childType == AspectTypes.LBRACKET || childType == AspectTypes.ROOT)) { + return Indent.getNormalIndent(); + } else if (parentPsi instanceof JastAddAspectCollectionContribution && (childType == AspectTypes.WHEN || childType == AspectTypes.TO || childType == AspectTypes.FOR)) { + return Indent.getNormalIndent(); + } + ASTNode nonBlankSuccecssor = myNode.getTreePrev(); + while (nonBlankSuccecssor != null && nonBlankSuccecssor.getElementType() == TokenType.WHITE_SPACE) { + nonBlankSuccecssor = nonBlankSuccecssor.getTreePrev(); + } + if (nonBlankSuccecssor != null && nonBlankSuccecssor.getElementType() == AspectTypes.ASSIGN) { + return Indent.getContinuationIndent(); + } + } + return Indent.getNoneIndent(); + } + + @Nullable + @Override + public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2) { + return spacingBuilder.getSpacing(this, child1, child2); + } + + @Override + public boolean isLeaf() { + return myNode.getFirstChildNode() == null; + } + + private static class AroundBlockBlock extends LeafBlock { + private final TextRange myRange; + + AroundBlockBlock(ASTNode node, Wrap wrap, Alignment alignment, Indent indent, TextRange range) { + super(node, wrap, alignment, indent); + myRange = range; + } + + @NotNull + @Override + public TextRange getTextRange() { + return myRange; + } + } + + private static class JavaBlockInjectedBlockBuilder extends InjectedLanguageBlockBuilder { + @Override + public CodeStyleSettings getSettings() { + return CodeStyleSettings.getDefaults(); + } + + @Override + public boolean canProcessFragment(String text, ASTNode injectionHost) { + return true; + } + + @Override + public Block createBlockBeforeInjection(ASTNode node, Wrap wrap, Alignment alignment, Indent indent, TextRange range) { + return new AroundBlockBlock(node, wrap, alignment, indent, range); + } + + @Override + public Block createBlockAfterInjection(ASTNode node, Wrap wrap, Alignment alignment, Indent indent, TextRange range) { + return new AroundBlockBlock(node, wrap, alignment, Indent.getNoneIndent(), range); + } + } + +} diff --git a/src/main/java/org/jastadd/tooling/aspect/AspectFormattingModelBuilder.java b/src/main/java/org/jastadd/tooling/aspect/AspectFormattingModelBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..fa469ff2afb3027ad6800fbc1dc8b35f9cfaca50 --- /dev/null +++ b/src/main/java/org/jastadd/tooling/aspect/AspectFormattingModelBuilder.java @@ -0,0 +1,29 @@ +package org.jastadd.tooling.aspect; + +import com.intellij.formatting.*; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import org.jastadd.tooling.aspect.psi.AspectTypes; +import org.jetbrains.annotations.NotNull; + +public class AspectFormattingModelBuilder implements FormattingModelBuilder { + + private static SpacingBuilder createSpaceBuilder(CodeStyleSettings settings) { + return new SpacingBuilder(settings, Aspect.INSTANCE) + .before(AspectTypes.ASPECT).none() + .after(AspectTypes.ASPECT).spaces(1) + .after(AspectTypes.LBRACE).none(); + } + + @Override + public @NotNull FormattingModel createModel(@NotNull FormattingContext formattingContext) { + final CodeStyleSettings codeStyleSettings = formattingContext.getCodeStyleSettings(); + return FormattingModelProvider + .createFormattingModelForPsiFile(formattingContext.getContainingFile(), + new AspectBlock(formattingContext.getNode(), + Wrap.createWrap(WrapType.NONE, false), + Alignment.createAlignment(), + createSpaceBuilder(codeStyleSettings)), + codeStyleSettings); + } + +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 01ee6c38d725034ee421dca47285c63dcf311649..a9b7feec56cba1ca3ce62fdb1bbb238ad4fef635 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -87,6 +87,8 @@ <lang.elementManipulator forClass="org.jastadd.tooling.aspect.psi.JastAddAspectClassOrInterfaceType" implementationClass="org.jastadd.tooling.aspect.psi.JastAddAspectClassOrInterfaceTypeManipulator"/> + + <lang.formatter language="JastAddAspect" implementationClass="org.jastadd.tooling.aspect.AspectFormattingModelBuilder"/> </extensions> <actions>