diff --git a/src/main/kotlin/org/domaframework/doma/intellij/extension/expr/SqlElExtensions.kt b/src/main/kotlin/org/domaframework/doma/intellij/extension/expr/SqlElExtensions.kt index bed3ec52..4d6cad8f 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/extension/expr/SqlElExtensions.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/extension/expr/SqlElExtensions.kt @@ -18,10 +18,15 @@ package org.domaframework.doma.intellij.extension.expr import com.intellij.psi.PsiElement import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.elementType +import org.domaframework.doma.intellij.psi.SqlCustomElCommentExpr import org.domaframework.doma.intellij.psi.SqlElClass +import org.domaframework.doma.intellij.psi.SqlElElseifDirective +import org.domaframework.doma.intellij.psi.SqlElForDirective +import org.domaframework.doma.intellij.psi.SqlElIfDirective import org.domaframework.doma.intellij.psi.SqlElPrimaryExpr import org.domaframework.doma.intellij.psi.SqlElStaticFieldAccessExpr import org.domaframework.doma.intellij.psi.SqlTypes +import kotlin.invoke val SqlElStaticFieldAccessExpr.accessElements: List get() { @@ -43,3 +48,13 @@ val SqlElStaticFieldAccessExpr.fqdn: String val fqdn = PsiTreeUtil.getChildrenOfTypeAsList(elClazz, PsiElement::class.java) return fqdn.toList().joinToString("") { it.text } } + +fun SqlCustomElCommentExpr.isConditionOrLoopDirective(): Boolean = + PsiTreeUtil.getChildOfType(this, SqlElIfDirective::class.java) != null || + PsiTreeUtil.getChildOfType(this, SqlElForDirective::class.java) != null || + PsiTreeUtil.getChildOfType( + this, + SqlElElseifDirective::class.java, + ) != null || + this.findElementAt(2)?.elementType == SqlTypes.EL_END || + this.findElementAt(2)?.elementType == SqlTypes.EL_ELSE diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlBlockBuilder.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlBlockBuilder.kt index 64cc68df..d9ad3434 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlBlockBuilder.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlBlockBuilder.kt @@ -16,7 +16,8 @@ package org.domaframework.doma.intellij.formatter import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlSubGroupBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElBlockCommentBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock open class SqlBlockBuilder { private val groupTopNodeIndexHistory = mutableListOf>() @@ -25,6 +26,8 @@ open class SqlBlockBuilder { fun getGroupTopNodeIndexHistory(): List> = groupTopNodeIndexHistory + fun getLastGroup(): SqlBlock? = groupTopNodeIndexHistory.lastOrNull()?.second + fun addGroupTopNodeIndexHistory(block: Pair) { groupTopNodeIndexHistory.add(block) } @@ -37,19 +40,21 @@ open class SqlBlockBuilder { if (commentBlocks.isNotEmpty()) { var index = 0 commentBlocks.forEach { block -> - val indentLen = - if (index == 0 && - baseIndent.parentBlock is SqlSubGroupBlock && - baseIndent.parentBlock?.childBlocks?.size == 1 - ) { - 1 - } else { - baseIndent.indent.indentLen - } - block.indent.indentLevel = IndentType.NONE - block.indent.indentLen = indentLen - block.indent.groupIndentLen = 0 - index++ + if (block !is SqlElBlockCommentBlock) { + val indentLen = + if (index == 0 && + baseIndent.parentBlock is SqlSubGroupBlock && + baseIndent.parentBlock?.childBlocks?.size == 1 + ) { + 1 + } else { + baseIndent.indent.indentLen + } + block.indent.indentLevel = IndentType.NONE + block.indent.indentLen = indentLen + block.indent.groupIndentLen = 0 + index++ + } } commentBlocks.clear() } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlBlockUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlBlockUtil.kt new file mode 100644 index 00000000..d26f6d09 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlBlockUtil.kt @@ -0,0 +1,286 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiComment +import com.intellij.psi.util.PsiTreeUtil +import org.domaframework.doma.intellij.extension.expr.isConditionOrLoopDirective +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.SqlBlockCommentBlock +import org.domaframework.doma.intellij.formatter.block.SqlColumnBlock +import org.domaframework.doma.intellij.formatter.block.SqlCommaBlock +import org.domaframework.doma.intellij.formatter.block.SqlCommentBlock +import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock +import org.domaframework.doma.intellij.formatter.block.SqlTableBlock +import org.domaframework.doma.intellij.formatter.block.SqlWordBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElBlockCommentBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock +import org.domaframework.doma.intellij.formatter.block.group.SqlColumnDefinitionRawGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlCreateKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInlineGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInlineSecondGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInsertKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlJoinGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlUpdateKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnDefinitionGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlDataTypeParamBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlFunctionParamBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlInsertColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlParallelListBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateValueGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlViewGroupBlock +import org.domaframework.doma.intellij.psi.SqlCustomElCommentExpr +import org.domaframework.doma.intellij.psi.SqlTypes + +class SqlBlockUtil( + private val sqlBlock: SqlBlock, +) { + val wrap = sqlBlock.wrap + val alignment = sqlBlock.alignment + val spacingBuilder = sqlBlock.spacingBuilder + + fun getKeywordBlock( + child: ASTNode, + lastGroupBlock: SqlBlock?, + ): SqlBlock { + // Because we haven't yet set the parent-child relationship of the block, + // the parent group references groupTopNodeIndexHistory. + val indentLevel = SqlKeywordUtil.getIndentType(child.text) + val keywordText = child.text.lowercase() + if (indentLevel.isNewLineGroup()) { + when (indentLevel) { + IndentType.JOIN -> { + return if (SqlKeywordUtil.isJoinKeyword(child.text)) { + SqlJoinGroupBlock(child, wrap, alignment, spacingBuilder) + } else if (lastGroupBlock is SqlJoinGroupBlock) { + SqlKeywordBlock(child, IndentType.ATTACHED, wrap, alignment, spacingBuilder) + } else { + SqlJoinGroupBlock(child, wrap, alignment, spacingBuilder) + } + } + + IndentType.INLINE_SECOND -> { + return SqlInlineSecondGroupBlock(child, wrap, alignment, spacingBuilder) + } + + IndentType.TOP -> { + if (keywordText == "create") { + return SqlCreateKeywordGroupBlock(child, wrap, alignment, spacingBuilder) + } + if (keywordText == "insert") { + return SqlInsertKeywordGroupBlock(child, wrap, alignment, spacingBuilder) + } + + return SqlKeywordGroupBlock(child, indentLevel, wrap, alignment, spacingBuilder) + } + + IndentType.SECOND -> { + return if (keywordText == "set") { + SqlUpdateKeywordGroupBlock(child, wrap, alignment, spacingBuilder) + } else { + SqlKeywordGroupBlock(child, indentLevel, wrap, alignment, spacingBuilder) + } + } + + else -> { + return SqlKeywordGroupBlock(child, indentLevel, wrap, alignment, spacingBuilder) + } + } + } + + when (indentLevel) { + IndentType.INLINE -> { + if (!SqlKeywordUtil.isSetLineKeyword( + child.text, + lastGroupBlock?.node?.text ?: "", + ) + ) { + return SqlInlineGroupBlock(child, wrap, alignment, spacingBuilder) + } + } + + IndentType.ATTACHED -> { + if (lastGroupBlock is SqlCreateKeywordGroupBlock) { + lastGroupBlock.setCreateQueryType(child.text) + return SqlKeywordBlock(child, indentLevel, wrap, alignment, spacingBuilder) + } + } + + IndentType.OPTIONS -> { + if (child.text.lowercase() == "as") { + val parentCreateBlock = + lastGroupBlock as? SqlCreateKeywordGroupBlock + ?: lastGroupBlock?.parentBlock as? SqlCreateKeywordGroupBlock + if (parentCreateBlock != null && parentCreateBlock.createType == CreateQueryType.VIEW) { + return SqlViewGroupBlock(child, wrap, alignment, spacingBuilder) + } + } + } + + else -> return SqlKeywordBlock(child, indentLevel, wrap, alignment, spacingBuilder) + } + return SqlKeywordBlock(child, indentLevel, wrap, alignment, spacingBuilder) + } + + fun getSubGroupBlock( + lastGroup: SqlBlock?, + child: ASTNode, + ): SqlBlock { + if (child.treePrev.elementType == SqlTypes.WORD) { + return SqlFunctionParamBlock(child, wrap, alignment, spacingBuilder) + } + + when (lastGroup) { + is SqlKeywordGroupBlock -> { + val lastKeyword = + lastGroup.childBlocks + .lastOrNull { SqlKeywordUtil.isOptionSqlKeyword(it.node.text) } + if (lastKeyword != null && lastKeyword.node.text.lowercase() == "in") { + return SqlParallelListBlock(child, wrap, alignment, spacingBuilder) + } + if (lastGroup is SqlCreateKeywordGroupBlock) { + return SqlColumnDefinitionGroupBlock(child, wrap, alignment, spacingBuilder) + } + if (lastGroup is SqlInsertKeywordGroupBlock) { + return SqlInsertColumnGroupBlock(child, wrap, alignment, spacingBuilder) + } + if (lastGroup is SqlUpdateKeywordGroupBlock) { + return if (lastGroup.childBlocks.firstOrNull { it is SqlUpdateColumnGroupBlock } == null) { + SqlUpdateColumnGroupBlock(child, wrap, alignment, spacingBuilder) + } else if (lastGroup.childBlocks.lastOrNull { it is SqlUpdateColumnGroupBlock } != null) { + SqlUpdateValueGroupBlock(child, wrap, alignment, spacingBuilder) + } else { + SqlSubQueryGroupBlock(child, wrap, alignment, spacingBuilder) + } + } + return SqlSubQueryGroupBlock(child, wrap, alignment, spacingBuilder) + } + + is SqlColumnDefinitionRawGroupBlock -> + return SqlDataTypeParamBlock(child, wrap, alignment, spacingBuilder) + + else -> + return SqlSubQueryGroupBlock(child, wrap, alignment, spacingBuilder) + } + } + + fun getCommaGroupBlock( + lastGroup: SqlBlock?, + child: ASTNode, + ): SqlBlock = + when (lastGroup) { + is SqlColumnDefinitionGroupBlock, is SqlColumnDefinitionRawGroupBlock -> + SqlColumnDefinitionRawGroupBlock( + child, + wrap, + alignment, + spacingBuilder, + ) + + is SqlColumnGroupBlock, is SqlKeywordGroupBlock -> { + if (lastGroup.indent.indentLevel == IndentType.SECOND) { + SqlCommaBlock(child, wrap, alignment, spacingBuilder) + } else { + SqlColumnGroupBlock(child, wrap, alignment, spacingBuilder) + } + } + + else -> SqlCommaBlock(child, wrap, alignment, spacingBuilder) + } + + fun getWordBlock( + lastGroup: SqlBlock?, + child: ASTNode, + ): SqlBlock = + when (lastGroup) { + is SqlKeywordGroupBlock -> { + when { + SqlKeywordUtil.isBeforeTableKeyword(lastGroup.node.text) -> + SqlTableBlock( + child, + wrap, + alignment, + spacingBuilder, + ) + + else -> SqlWordBlock(child, wrap, alignment, spacingBuilder) + } + } + + is SqlColumnDefinitionGroupBlock -> { + lastGroup.alignmentColumnName = child.text + SqlColumnDefinitionRawGroupBlock( + child, + wrap, + alignment, + spacingBuilder, + ) + } + + is SqlColumnDefinitionRawGroupBlock -> { + if (lastGroup.childBlocks.isEmpty()) { + lastGroup.columnName = child.text + SqlColumnBlock( + child, + wrap, + alignment, + spacingBuilder, + ) + } else { + SqlWordBlock(child, wrap, alignment, spacingBuilder) + } + } + + else -> SqlWordBlock(child, wrap, alignment, spacingBuilder) + } + + fun getBlockCommentBlock( + child: ASTNode, + blockCommentSpacingBuilder: SqlCustomSpacingBuilder?, + ): SqlCommentBlock { + if (PsiTreeUtil.getChildOfType(child.psi, PsiComment::class.java) != null) { + return SqlBlockCommentBlock( + child, + wrap, + alignment, + spacingBuilder, + ) + } + if (child.psi is SqlCustomElCommentExpr && + (child.psi as SqlCustomElCommentExpr).isConditionOrLoopDirective() + ) { + return SqlElConditionLoopCommentBlock( + child, + wrap, + alignment, + blockCommentSpacingBuilder, + spacingBuilder, + ) + } + return SqlElBlockCommentBlock( + child, + wrap, + alignment, + blockCommentSpacingBuilder, + spacingBuilder, + ) + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlCustomSpacingBuilder.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlCustomSpacingBuilder.kt index a6b2d593..324f1d0c 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlCustomSpacingBuilder.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlCustomSpacingBuilder.kt @@ -24,7 +24,12 @@ import org.domaframework.doma.intellij.formatter.block.SqlColumnBlock import org.domaframework.doma.intellij.formatter.block.SqlRightPatternBlock import org.domaframework.doma.intellij.formatter.block.SqlWhitespaceBlock import org.domaframework.doma.intellij.formatter.block.group.SqlColumnDefinitionRawGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnDefinitionGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlDataTypeParamBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlParallelListBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateValueGroupBlock class SqlCustomSpacingBuilder { companion object { @@ -69,10 +74,14 @@ class SqlCustomSpacingBuilder { child1: SqlBlock?, child2: SqlBlock, ): Spacing? { - val indentLen: Int = child2.indent.indentLen + if (child2.parentBlock is SqlParallelListBlock) { + return nonSpacing + } + when (child1) { - null -> return Spacing.createSpacing(0, 0, 0, false, 0, 0) + null -> return nonSpacing is SqlWhitespaceBlock -> { + val indentLen: Int = child2.indent.indentLen val afterNewLine = child1.node.text.substringAfterLast("\n", "") if (child1.node.text.contains("\n")) { val currentIndent = afterNewLine.length @@ -85,14 +94,15 @@ class SqlCustomSpacingBuilder { return Spacing.createSpacing(newIndent, newIndent, 0, false, 0, 0) } } + else -> { - return Spacing.createSpacing(indentLen, indentLen, 1, false, 0, 1) + return getSpacing(child2) } } return null } - fun getSpacing(child2: SqlNewGroupBlock): Spacing? = + fun getSpacing(child2: SqlBlock): Spacing = Spacing.createSpacing( child2.indent.indentLen, child2.indent.indentLen, @@ -112,8 +122,29 @@ class SqlCustomSpacingBuilder { return Spacing.createSpacing(indentLen, indentLen, 0, false, 0, 0) } - fun getSpacingColumnDefinitionRawEndRight(child: SqlRightPatternBlock): Spacing? { - val indentLen = child.indent.indentLen - return Spacing.createSpacing(indentLen, indentLen, 0, false, 0, 0) + fun getSpacingRightPattern(block: SqlRightPatternBlock): Spacing? { + return when { + block.parentBlock is SqlColumnDefinitionGroupBlock || + block.parentBlock is SqlUpdateColumnGroupBlock || + block.parentBlock is SqlUpdateValueGroupBlock -> { + return getSpacing(block) + } + + block.parentBlock is SqlParallelListBlock -> { + if (block.parentBlock + ?.childBlocks + ?.dropLast(1) + ?.lastOrNull() is SqlKeywordGroupBlock + ) { + return normalSpacing + } + return nonSpacing + } + + block.parentBlock is SqlDataTypeParamBlock -> nonSpacing + + block.preSpaceRight -> normalSpacing + else -> nonSpacing + } } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatPreProcessor.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatPreProcessor.kt index b5d6f95e..a7e3a826 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatPreProcessor.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatPreProcessor.kt @@ -28,7 +28,9 @@ import com.intellij.psi.impl.source.codeStyle.PreFormatProcessor import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.elementType import com.intellij.psi.util.prevLeafs +import org.domaframework.doma.intellij.extension.expr.isConditionOrLoopDirective import org.domaframework.doma.intellij.psi.SqlBlockComment +import org.domaframework.doma.intellij.psi.SqlCustomElCommentExpr import org.domaframework.doma.intellij.psi.SqlTypes import org.domaframework.doma.intellij.setting.SqlLanguage import org.domaframework.doma.intellij.state.DomaToolsFunctionEnableSettings @@ -90,14 +92,14 @@ class SqlFormatPreProcessor : PreFormatProcessor { } SqlTypes.RIGHT_PAREN -> { - newKeyword = getRightPatternNewText(it, newKeyword, createQueryType) + newKeyword = getRightPatternNewText(it, newKeyword, replaceKeywordList[keywordIndex - 1], createQueryType) } SqlTypes.WORD -> { newKeyword = getWordNewText(it, newKeyword, createQueryType) } - SqlTypes.COMMA -> { + SqlTypes.COMMA, SqlTypes.BLOCK_COMMENT, SqlTypes.OTHER -> { newKeyword = getNewLineString(it.prevSibling, getUpperText(it)) } } @@ -192,25 +194,29 @@ class SqlFormatPreProcessor : PreFormatProcessor { private fun getRightPatternNewText( element: PsiElement, - newKeyword: String, + keyword: String, + nextKeyword: PsiElement, createQueryType: CreateQueryType, ): String { - var newKeyword1 = newKeyword - val prefixElements = - getElementsBeforeKeyword(element.prevLeafs.toList()) { it.elementType == SqlTypes.LEFT_PAREN } - val containsColumnRaw = - prefixElements.findLast { isColumnDefinedRawElementType(it) } != null - newKeyword1 = - if (createQueryType == CreateQueryType.TABLE) { + var newKeyword = keyword + val elementText = element.text + if (createQueryType == CreateQueryType.TABLE) { + val prefixElements = + getElementsBeforeKeyword(element.prevLeafs.toList()) { it.elementType == SqlTypes.LEFT_PAREN } + val containsColumnRaw = + prefixElements.findLast { isColumnDefinedRawElementType(it) } != null + newKeyword = if (containsColumnRaw) { - getNewLineString(element.prevSibling, getUpperText(element)) + getNewLineString(element.prevSibling, elementText) } else { - getUpperText(element) + elementText } - } else { - getUpperText(element) - } - return newKeyword1 + } else if (nextKeyword.text.lowercase() == "set") { + newKeyword = getNewLineString(element.prevSibling, elementText) + } else { + newKeyword = elementText + } + return newKeyword } private fun getWordNewText( @@ -329,6 +335,23 @@ private class SqlFormatVisitor : PsiRecursiveElementVisitor() { SqlTypes.KEYWORD, SqlTypes.COMMA, SqlTypes.LEFT_PAREN, SqlTypes.RIGHT_PAREN, SqlTypes.WORD -> { replaces.add(element) } + SqlTypes.OTHER -> { + if (element.text == "=") { + val updateSetKeyword = + replaces + .lastOrNull { it.elementType == SqlTypes.KEYWORD } + if (updateSetKeyword?.text?.lowercase() == "set") { + replaces.add(element) + } + } + } + SqlTypes.BLOCK_COMMENT -> + if ( + element is SqlCustomElCommentExpr && + element.isConditionOrLoopDirective() + ) { + replaces.add(element) + } } } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlFormattingModelBuilder.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlFormattingModelBuilder.kt index 2a1eda37..c6e62ed4 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlFormattingModelBuilder.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlFormattingModelBuilder.kt @@ -86,16 +86,18 @@ class SqlFormattingModelBuilder : FormattingModelBuilder { .spacing(1, 1, 0, false, 0) .around(SqlTypes.ASTERISK) .spacing(1, 1, 0, false, 0) + .before(SqlTypes.LEFT_PAREN) + .spacing(1, 1, 0, false, 0) private fun createCustomSpacingBuilder(): SqlCustomSpacingBuilder = SqlCustomSpacingBuilder() .withSpacing( - TokenType.WHITE_SPACE, - SqlTypes.KEYWORD, + SqlTypes.NUMBER, + SqlTypes.COMMA, SqlCustomSpacingBuilder.nonSpacing, ).withSpacing( - SqlTypes.WORD, - TokenType.WHITE_SPACE, + SqlTypes.STRING, + SqlTypes.COMMA, SqlCustomSpacingBuilder.nonSpacing, ).withSpacing( SqlTypes.WORD, @@ -109,10 +111,6 @@ class SqlFormattingModelBuilder : FormattingModelBuilder { SqlTypes.WORD, SqlTypes.RIGHT_PAREN, SqlCustomSpacingBuilder.nonSpacing, - ).withSpacing( - SqlTypes.OTHER, - TokenType.WHITE_SPACE, - SqlCustomSpacingBuilder.nonSpacing, ).withSpacing( SqlTypes.ASTERISK, TokenType.WHITE_SPACE, diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlKeywordUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlKeywordUtil.kt index fadc8bcb..c809b9f3 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlKeywordUtil.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlKeywordUtil.kt @@ -81,6 +81,7 @@ class SqlKeywordUtil { private val SECOND_KEYWORD = setOf( + "set", "from", "where", "order", diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlBlock.kt index f5944559..b4cdc882 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlBlock.kt @@ -23,33 +23,30 @@ import com.intellij.formatting.Spacing import com.intellij.formatting.SpacingBuilder import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode -import com.intellij.psi.PsiComment import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.formatter.common.AbstractBlock -import com.intellij.psi.util.PsiTreeUtil -import org.domaframework.doma.intellij.formatter.CreateQueryType import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.SqlBlockBuilder +import org.domaframework.doma.intellij.formatter.SqlBlockUtil import org.domaframework.doma.intellij.formatter.SqlCustomSpacingBuilder import org.domaframework.doma.intellij.formatter.SqlKeywordUtil import org.domaframework.doma.intellij.formatter.block.expr.SqlElBlockCommentBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElDotBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.expr.SqlElSymbolBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlColumnDefinitionGroupBlock import org.domaframework.doma.intellij.formatter.block.group.SqlColumnDefinitionRawGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlColumnGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlCreateKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlDataTypeParamBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlInlineGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlInlineSecondGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlInsertColumnGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlInsertKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlJoinGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlSubGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlSubQueryGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlViewGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInlineGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInlineSecondGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnDefinitionGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlDataTypeParamBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlFunctionParamBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlInsertColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlParallelListBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlViewGroupBlock import org.domaframework.doma.intellij.psi.SqlTypes open class SqlBlock( @@ -81,6 +78,7 @@ open class SqlBlock( ) private val blockBuilder = SqlBlockBuilder() + protected val blockUtil = SqlBlockUtil(this) protected open val pendingCommentBlocks = mutableListOf() @@ -148,11 +146,11 @@ open class SqlBlock( lastGroup: SqlBlock?, ): Boolean = isNewLineGroupBlock(childBlock, child, lastGroup) || - childBlock.node.elementType == SqlTypes.COMMA || childBlock is SqlInsertColumnGroupBlock || childBlock is SqlColumnDefinitionRawGroupBlock || childBlock is SqlColumnDefinitionGroupBlock || - (childBlock is SqlRightPatternBlock && childBlock.isNeedBeforeWhiteSpace(lastGroup)) || + (childBlock is SqlOtherBlock && childBlock.isUpdateColumnSubstitutions) || + (childBlock is SqlRightPatternBlock && childBlock.isNewLine(lastGroup)) || ( ( childBlock is SqlLineCommentBlock || @@ -160,7 +158,7 @@ open class SqlBlock( ) && child.treePrev.text.contains("\n") ) || - (childBlock is SqlElBlockCommentBlock && childBlock.isConditionLoopBlock) + (childBlock is SqlElConditionLoopCommentBlock) private fun setRightSpace(currentBlock: SqlBlock?) { val rightBlock = currentBlock as? SqlRightPatternBlock @@ -174,11 +172,7 @@ open class SqlBlock( if (lastGroup?.indent?.indentLevel == IndentType.JOIN) { lastGroup.node.text } else { - lastGroup - ?.childBlocks - ?.lastOrNull { it.node.elementType == SqlTypes.KEYWORD } - ?.node - ?.text ?: lastGroup?.node?.text ?: "" + getLastGroupKeywordText(lastGroup) } val isSetLineGroup = @@ -195,16 +189,21 @@ open class SqlBlock( child: ASTNode, lastGroup: SqlBlock?, ): Boolean { + if (childBlock is SqlCommaBlock && + ( + lastGroup is SqlParallelListBlock || + lastGroup?.parentBlock is SqlParallelListBlock + ) + ) { + return false + } + val isNewGroupType = childBlock.indent.indentLevel.isNewLineGroup() val lastKeywordText = if (lastGroup?.indent?.indentLevel == IndentType.JOIN) { lastGroup.node.text } else { - lastGroup - ?.childBlocks - ?.lastOrNull { it.node.elementType == SqlTypes.KEYWORD } - ?.node - ?.text ?: lastGroup?.node?.text ?: "" + getLastGroupKeywordText(lastGroup) } val isSetLineGroup = @@ -221,6 +220,17 @@ open class SqlBlock( return false } + /** + * Searches for a keyword element in the most recent group block and returns its text. + * If not found, returns the text of the group block itself. + */ + private fun getLastGroupKeywordText(lastGroup: SqlBlock?): String = + lastGroup + ?.childBlocks + ?.lastOrNull { it.node.elementType == SqlTypes.KEYWORD } + ?.node + ?.text ?: lastGroup?.node?.text ?: "" + protected open fun updateSearchKeywordLevelHistory( childBlock: SqlBlock, child: ASTNode, @@ -368,6 +378,17 @@ open class SqlBlock( } } + is SqlElConditionLoopCommentBlock -> { + if (lastGroupBlock is SqlCommaBlock || lastGroupBlock is SqlElConditionLoopCommentBlock) { + blockBuilder.removeLastGroupTopNodeIndexHistory() + } + setParentGroups( + childBlock, + ) { history -> + return@setParentGroups history.last().second + } + } + is SqlWordBlock, is SqlOtherBlock, is SqlLineCommentBlock, is SqlBlockCommentBlock -> { setParentGroups( childBlock, @@ -424,6 +445,17 @@ open class SqlBlock( } } + is SqlCommaBlock -> { + if (lastGroupBlock is SqlCommaBlock) { + blockBuilder.removeLastGroupTopNodeIndexHistory() + } + setParentGroups( + childBlock, + ) { history -> + return@setParentGroups history.last().second + } + } + else -> { setParentGroups( childBlock, @@ -442,7 +474,7 @@ open class SqlBlock( getParentGroup(blockBuilder.getGroupTopNodeIndexHistory() as MutableList>) childBlock.setParentGroupBlock(parentGroup) if (isNewGroup(childBlock) || - childBlock is SqlSubGroupBlock || + (childBlock is SqlSubGroupBlock) || childBlock is SqlViewGroupBlock || childBlock is SqlInlineGroupBlock || childBlock is SqlInlineSecondGroupBlock || @@ -460,106 +492,29 @@ open class SqlBlock( val lastGroup = blockBuilder.getLastGroupTopNodeIndexHistory()?.second return when (child.elementType) { SqlTypes.KEYWORD -> { - return getKeywordBlock(child) + return blockUtil.getKeywordBlock( + child, + blockBuilder.getLastGroupTopNodeIndexHistory()?.second, + ) } SqlTypes.DATATYPE -> SqlDataTypeBlock(child, wrap, alignment, spacingBuilder) SqlTypes.LEFT_PAREN -> { - if (lastGroup is SqlCreateKeywordGroupBlock && lastGroup.createType == CreateQueryType.TABLE) { - SqlColumnDefinitionGroupBlock(child, wrap, alignment, spacingBuilder) - } else if (lastGroup is SqlColumnDefinitionRawGroupBlock) { - SqlDataTypeParamBlock(child, wrap, alignment, spacingBuilder) - } else if (lastGroup is SqlInsertKeywordGroupBlock) { - SqlInsertColumnGroupBlock(child, wrap, alignment, spacingBuilder) - } else { - SqlSubQueryGroupBlock(child, wrap, alignment, spacingBuilder) - } + return blockUtil.getSubGroupBlock(lastGroup, child) } - SqlTypes.OTHER -> - return SqlOtherBlock(child, wrap, alignment, spacingBuilder) - - SqlTypes.DOT -> return SqlElDotBlock(child, wrap, alignment, spacingBuilder) - + SqlTypes.OTHER -> return SqlOtherBlock(child, wrap, alignment, spacingBuilder, blockBuilder.getLastGroup()) SqlTypes.RIGHT_PAREN -> return SqlRightPatternBlock(child, wrap, alignment, spacingBuilder) SqlTypes.COMMA -> { - return when (lastGroup) { - is SqlColumnDefinitionGroupBlock, is SqlColumnDefinitionRawGroupBlock -> - SqlColumnDefinitionRawGroupBlock( - child, - wrap, - alignment, - spacingBuilder, - ) - - is SqlColumnGroupBlock, is SqlKeywordGroupBlock -> SqlColumnGroupBlock(child, wrap, alignment, spacingBuilder) - - else -> SqlCommaBlock(child, wrap, alignment, spacingBuilder) - } + return blockUtil.getCommaGroupBlock(lastGroup, child) } - SqlTypes.WORD -> { - when (lastGroup) { - is SqlKeywordGroupBlock -> { - when { - SqlKeywordUtil.isBeforeTableKeyword(lastGroup.node.text) -> - SqlTableBlock( - child, - wrap, - alignment, - spacingBuilder, - ) - - else -> SqlWordBlock(child, wrap, alignment, spacingBuilder) - } - } - - is SqlColumnDefinitionGroupBlock -> { - lastGroup.alignmentColumnName = child.text - SqlColumnDefinitionRawGroupBlock( - child, - wrap, - alignment, - spacingBuilder, - ) - } - - is SqlColumnDefinitionRawGroupBlock -> { - if (lastGroup.childBlocks.isEmpty()) { - lastGroup.columnName = child.text - SqlColumnBlock( - child, - wrap, - alignment, - spacingBuilder, - ) - } else { - SqlWordBlock(child, wrap, alignment, spacingBuilder) - } - } - - else -> SqlWordBlock(child, wrap, alignment, spacingBuilder) - } - } + SqlTypes.WORD -> return blockUtil.getWordBlock(lastGroup, child) SqlTypes.BLOCK_COMMENT -> { - if (PsiTreeUtil.getChildOfType(child.psi, PsiComment::class.java) != null) { - return SqlBlockCommentBlock( - child, - wrap, - alignment, - spacingBuilder, - ) - } - return SqlElBlockCommentBlock( - child, - wrap, - alignment, - createBlockCommentSpacingBuilder(), - spacingBuilder, - ) + return blockUtil.getBlockCommentBlock(child, createBlockCommentSpacingBuilder()) } SqlTypes.LINE_COMMENT -> @@ -578,77 +533,6 @@ open class SqlBlock( } } - private fun getKeywordBlock(child: ASTNode): SqlBlock { - // Because we haven't yet set the parent-child relationship of the block, - // the parent group references groupTopNodeIndexHistory. - val indentLevel = SqlKeywordUtil.getIndentType(child.text) - val lastGroupBlock = blockBuilder.getLastGroupTopNodeIndexHistory()?.second - if (indentLevel.isNewLineGroup()) { - when (indentLevel) { - IndentType.JOIN -> { - return if (SqlKeywordUtil.isJoinKeyword(child.text)) { - SqlJoinGroupBlock(child, wrap, alignment, spacingBuilder) - } else if (lastGroupBlock is SqlJoinGroupBlock) { - SqlKeywordBlock(child, IndentType.ATTACHED, wrap, alignment, spacingBuilder) - } else { - SqlJoinGroupBlock(child, wrap, alignment, spacingBuilder) - } - } - - IndentType.INLINE_SECOND -> { - return SqlInlineSecondGroupBlock(child, wrap, alignment, spacingBuilder) - } - - IndentType.TOP -> { - if (child.text.lowercase() == "create") { - return SqlCreateKeywordGroupBlock(child, wrap, alignment, spacingBuilder) - } - if (child.text.lowercase() == "insert") { - return SqlInsertKeywordGroupBlock(child, wrap, alignment, spacingBuilder) - } - return SqlKeywordGroupBlock(child, indentLevel, wrap, alignment, spacingBuilder) - } - - else -> { - return SqlKeywordGroupBlock(child, indentLevel, wrap, alignment, spacingBuilder) - } - } - } - - when (indentLevel) { - IndentType.INLINE -> { - if (!SqlKeywordUtil.isSetLineKeyword( - child.text, - lastGroupBlock?.node?.text ?: "", - ) - ) { - return SqlInlineGroupBlock(child, wrap, alignment, spacingBuilder) - } - } - - IndentType.ATTACHED -> { - if (lastGroupBlock is SqlCreateKeywordGroupBlock) { - lastGroupBlock.setCreateQueryType(child.text) - return SqlKeywordBlock(child, indentLevel, wrap, alignment, spacingBuilder) - } - } - - IndentType.OPTIONS -> { - if (child.text.lowercase() == "as") { - val parentCreateBlock = - lastGroupBlock as? SqlCreateKeywordGroupBlock - ?: lastGroupBlock?.parentBlock as? SqlCreateKeywordGroupBlock - if (parentCreateBlock != null && parentCreateBlock.createType == CreateQueryType.VIEW) { - return SqlViewGroupBlock(child, wrap, alignment, spacingBuilder) - } - } - } - - else -> return SqlKeywordBlock(child, indentLevel, wrap, alignment, spacingBuilder) - } - return SqlKeywordBlock(child, indentLevel, wrap, alignment, spacingBuilder) - } - protected open fun createSpacingBuilder(): SqlCustomSpacingBuilder = SqlCustomSpacingBuilder() protected fun createBlockCommentSpacingBuilder(): SqlCustomSpacingBuilder = @@ -684,46 +568,47 @@ open class SqlBlock( child2: Block, ): Spacing? { if (!isEnableFormat()) return null + // The end of a line comment element is a newline, so just add a space for the indent. - if (child1 is SqlLineCommentBlock) { - if (child2 is SqlBlock) { - return Spacing.createSpacing(child2.indent.indentLen, child2.indent.indentLen, 0, false, 0) - } + if (child1 is SqlLineCommentBlock && child2 is SqlBlock) { + return SqlCustomSpacingBuilder().getSpacing(child2) } // Do not leave a space after the comment block of the bind variable if (child1 is SqlElBlockCommentBlock && child2 !is SqlCommentBlock) { - return Spacing.createSpacing(0, 0, 0, false, 0) + return SqlCustomSpacingBuilder.nonSpacing } if (child2 is SqlElBlockCommentBlock) { when (child1) { is SqlElBlockCommentBlock -> { - val indentLen = child2.indent.indentLen - return Spacing.createSpacing(indentLen, indentLen, 1, false, 0) + return SqlCustomSpacingBuilder().getSpacing(child2) } is SqlWhitespaceBlock -> { - val indentLen = child2.indent.indentLen - return Spacing.createSpacing(indentLen, indentLen, 0, false, 0) + return SqlCustomSpacingBuilder().getSpacing(child2) } else -> return SqlCustomSpacingBuilder.normalSpacing } } + if (child1 is SqlFunctionParamBlock) { + return SqlCustomSpacingBuilder.nonSpacing + } + + if (child2 is SqlOtherBlock) { + return SqlCustomSpacingBuilder().getSpacing(child2) + } + if (child1 is SqlWhitespaceBlock) { when (child2) { is SqlBlockCommentBlock, is SqlLineCommentBlock -> { - val indentLen = child2.indent.indentLen - return Spacing.createSpacing(indentLen, indentLen, 0, false, 0) + return SqlCustomSpacingBuilder().getSpacing(child2) } is SqlNewGroupBlock -> { - return SqlCustomSpacingBuilder() - .getSpacing( - child2, - )?.let { return it } + return SqlCustomSpacingBuilder().getSpacing(child2) } } } @@ -733,15 +618,12 @@ open class SqlBlock( is SqlSubQueryGroupBlock -> { if (child1 is SqlNewGroupBlock) { return SqlCustomSpacingBuilder.normalSpacing - } else { - // Remove spaces for parameter subgroups such as functions - SqlCustomSpacingBuilder.nonSpacing } } - else -> { - SqlCustomSpacingBuilder.normalSpacing - } + is SqlDataTypeParamBlock, is SqlFunctionParamBlock -> return SqlCustomSpacingBuilder.nonSpacing + + else -> return SqlCustomSpacingBuilder.normalSpacing } } @@ -750,16 +632,7 @@ open class SqlBlock( } if (child2 is SqlRightPatternBlock) { - return when { - child2.parentBlock is SqlColumnDefinitionGroupBlock -> - SqlCustomSpacingBuilder() - .getSpacingColumnDefinitionRawEndRight(child2) - ?.let { return it } - child2.parentBlock is SqlDataTypeParamBlock -> SqlCustomSpacingBuilder.nonSpacing - - child2.preSpaceRight -> SqlCustomSpacingBuilder.normalSpacing - else -> SqlCustomSpacingBuilder.nonSpacing - } + return SqlCustomSpacingBuilder().getSpacingRightPattern(child2) } if (child1 is SqlBlock && (child2 is SqlCommaBlock || child2 is SqlColumnGroupBlock)) { @@ -795,7 +668,7 @@ open class SqlBlock( } override fun getChildIndent(): Indent? = - if (!isEnableFormat()) { + if (isEnableFormat()) { Indent.getSpaceIndent(4) } else { Indent.getSpaceIndent(0) diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlColumnBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlColumnBlock.kt index f981f29e..20cfd46b 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlColumnBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlColumnBlock.kt @@ -21,7 +21,7 @@ import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.IndentType -import org.domaframework.doma.intellij.formatter.block.group.SqlColumnDefinitionGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnDefinitionGroupBlock class SqlColumnBlock( node: ASTNode, diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlCommaBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlCommaBlock.kt index fc65de27..3adfdd3c 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlCommaBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlCommaBlock.kt @@ -22,10 +22,14 @@ import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.IndentType -import org.domaframework.doma.intellij.formatter.block.group.SqlColumnGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlCreateKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlInsertKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlSubGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlCreateKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInsertKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlParallelListBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateValueGroupBlock +import org.domaframework.doma.intellij.psi.SqlTypes open class SqlCommaBlock( node: ASTNode, @@ -39,6 +43,13 @@ open class SqlCommaBlock( null, spacingBuilder, ) { + override val indent = + ElementIndent( + IndentType.COMMA, + 0, + 0, + ) + override fun setParentGroupBlock(block: SqlBlock?) { super.setParentGroupBlock(block) indent.indentLevel = IndentType.COMMA @@ -53,7 +64,15 @@ open class SqlCommaBlock( override fun createBlockIndentLen(): Int { parentBlock?.let { parent -> if (parent is SqlSubGroupBlock) { + if (parent is SqlParallelListBlock) { + return 0 + } + val parentIndentLen = parent.indent.groupIndentLen + if (parent is SqlUpdateColumnGroupBlock || parent is SqlUpdateValueGroupBlock) { + return parentIndentLen + } + val grand = parent.parentBlock grand?.let { grand -> if (grand is SqlCreateKeywordGroupBlock) { @@ -72,8 +91,19 @@ open class SqlCommaBlock( } return parentIndentLen } else { - val parentLen = parent.node.text.length - return parent.indent.groupIndentLen.plus(parentLen.plus(1)) + var prevLen = 0 + parent.childBlocks + .filter { it.node.elementType == SqlTypes.KEYWORD } + .forEach { prev -> + prevLen = + prevLen.plus( + prev.node.text.length + .plus(1), + ) + } + return parent.indent.groupIndentLen + .plus(prevLen) + .plus(1) } } return 1 diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlLineCommentBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlLineCommentBlock.kt index a13b8c75..77cf9491 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlLineCommentBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlLineCommentBlock.kt @@ -21,7 +21,7 @@ import com.intellij.formatting.SpacingBuilder import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlSubQueryGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock open class SqlLineCommentBlock( node: ASTNode, diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlOtherBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlOtherBlock.kt index 953113bb..38d70bb1 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlOtherBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlOtherBlock.kt @@ -22,12 +22,14 @@ import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.IndentType +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateColumnGroupBlock open class SqlOtherBlock( node: ASTNode, wrap: Wrap?, alignment: Alignment?, spacingBuilder: SpacingBuilder, + lastGroup: SqlBlock? = null, ) : SqlBlock( node, wrap, @@ -35,6 +37,8 @@ open class SqlOtherBlock( null, spacingBuilder, ) { + var isUpdateColumnSubstitutions = isBeforeUpdateValuesBlock(lastGroup) + override val indent = ElementIndent( IndentType.NONE, @@ -45,7 +49,7 @@ open class SqlOtherBlock( override fun setParentGroupBlock(block: SqlBlock?) { super.setParentGroupBlock(block) indent.indentLevel = IndentType.NONE - indent.indentLen = 0 + indent.indentLen = createIndentLen() indent.groupIndentLen = 0 } @@ -53,5 +57,17 @@ open class SqlOtherBlock( override fun getIndent(): Indent? = Indent.getSpaceIndent(indent.indentLen) + private fun createIndentLen(): Int { + if (isUpdateColumnSubstitutions) { + parentBlock?.let { return it.indent.groupIndentLen.plus(1) } + ?: return indent.indentLen + } else { + return 1 + } + } + + fun isBeforeUpdateValuesBlock(lastGroupBlock: SqlBlock?): Boolean = + lastGroupBlock?.childBlocks?.lastOrNull() is SqlUpdateColumnGroupBlock + override fun isLeaf(): Boolean = true } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlRightPatternBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlRightPatternBlock.kt index 24642c18..882217d3 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlRightPatternBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlRightPatternBlock.kt @@ -21,10 +21,13 @@ import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.IndentType -import org.domaframework.doma.intellij.formatter.block.group.SqlColumnDefinitionGroupBlock import org.domaframework.doma.intellij.formatter.block.group.SqlColumnDefinitionRawGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlInsertColumnGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlInsertKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInsertKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlUpdateKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnDefinitionGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlInsertColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateValueGroupBlock import org.domaframework.doma.intellij.psi.SqlTypes /** @@ -82,11 +85,21 @@ open class SqlRightPatternBlock( override fun buildChildren(): MutableList = mutableListOf() - override fun createBlockIndentLen(): Int = parentBlock?.indent?.groupIndentLen ?: 1 + override fun createBlockIndentLen(): Int = + if (parentBlock is SqlUpdateColumnGroupBlock || parentBlock is SqlUpdateValueGroupBlock) { + parentBlock?.indent?.indentLen ?: 1 + } else { + parentBlock?.indent?.groupIndentLen ?: 1 + } override fun isLeaf(): Boolean = true - fun isNeedBeforeWhiteSpace(lastGroup: SqlBlock?): Boolean = + fun isNewLine(lastGroup: SqlBlock?): Boolean = lastGroup is SqlColumnDefinitionGroupBlock || - lastGroup is SqlColumnDefinitionRawGroupBlock + lastGroup is SqlColumnDefinitionRawGroupBlock || + lastGroup?.parentBlock is SqlUpdateKeywordGroupBlock || + lastGroup?.parentBlock is SqlUpdateColumnGroupBlock || + lastGroup is SqlUpdateColumnGroupBlock || + lastGroup is SqlUpdateValueGroupBlock || + lastGroup?.parentBlock is SqlUpdateValueGroupBlock } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlWordBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlWordBlock.kt index aadd0335..2ad23efc 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlWordBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlWordBlock.kt @@ -22,7 +22,7 @@ import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.IndentType -import org.domaframework.doma.intellij.formatter.block.group.SqlSubQueryGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock open class SqlWordBlock( node: ASTNode, diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElBlockCommentBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElBlockCommentBlock.kt index 02576645..8b03e428 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElBlockCommentBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElBlockCommentBlock.kt @@ -33,7 +33,7 @@ import org.domaframework.doma.intellij.formatter.block.SqlBlockCommentBlock import org.domaframework.doma.intellij.formatter.block.SqlCommentBlock import org.domaframework.doma.intellij.formatter.block.SqlOperationBlock import org.domaframework.doma.intellij.formatter.block.SqlUnknownBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlSubQueryGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock import org.domaframework.doma.intellij.psi.SqlElElseifDirective import org.domaframework.doma.intellij.psi.SqlElForDirective import org.domaframework.doma.intellij.psi.SqlElIfDirective @@ -48,11 +48,11 @@ enum class SqlDirectiveType { Variable, } -class SqlElBlockCommentBlock( +open class SqlElBlockCommentBlock( node: ASTNode, wrap: Wrap?, alignment: Alignment?, - val customSpacingBuilder: SqlCustomSpacingBuilder?, + open val customSpacingBuilder: SqlCustomSpacingBuilder?, spacingBuilder: SpacingBuilder, ) : SqlCommentBlock( node, @@ -60,7 +60,7 @@ class SqlElBlockCommentBlock( alignment, spacingBuilder, ) { - var isConditionLoopBlock = getConditionOrLoopBlock(node) + // open var isConditionLoopBlock = getConditionOrLoopBlock(node) override val indent = ElementIndent( @@ -83,17 +83,6 @@ class SqlElBlockCommentBlock( if (child !is PsiWhiteSpace) { val block = getBlock(child) blocks.add(block) - if (!isConditionLoopBlock && - ( - child.elementType == SqlTypes.EL_IF_DIRECTIVE || - child.elementType == SqlTypes.EL_FOR_DIRECTIVE || - child.elementType == SqlTypes.EL_ELSEIF_DIRECTIVE || - child.elementType == SqlTypes.EL_ELSE || - child.elementType == SqlTypes.EL_END - ) - ) { - isConditionLoopBlock = true - } } child = child.treeNext } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElConditionLoopCommentBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElConditionLoopCommentBlock.kt new file mode 100644 index 00000000..dfd9c436 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElConditionLoopCommentBlock.kt @@ -0,0 +1,209 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.expr + +import com.intellij.formatting.Alignment +import com.intellij.formatting.Block +import com.intellij.formatting.Spacing +import com.intellij.formatting.SpacingBuilder +import com.intellij.formatting.Wrap +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiWhiteSpace +import com.intellij.psi.formatter.common.AbstractBlock +import org.domaframework.doma.intellij.formatter.IndentType +import org.domaframework.doma.intellij.formatter.SqlCustomSpacingBuilder +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.SqlBlockCommentBlock +import org.domaframework.doma.intellij.formatter.block.SqlOperationBlock +import org.domaframework.doma.intellij.formatter.block.SqlUnknownBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlCreateKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInsertKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock +import org.domaframework.doma.intellij.psi.SqlTypes + +class SqlElConditionLoopCommentBlock( + node: ASTNode, + wrap: Wrap?, + alignment: Alignment?, + override val customSpacingBuilder: SqlCustomSpacingBuilder?, + spacingBuilder: SpacingBuilder, +) : SqlElBlockCommentBlock( + node, + wrap, + alignment, + customSpacingBuilder, + spacingBuilder, + ) { + override val indent = + ElementIndent( + IndentType.NONE, + 0, + 0, + ) + + override fun setParentGroupBlock(block: SqlBlock?) { + super.setParentGroupBlock(block) + indent.indentLevel = IndentType.NONE + indent.indentLen = createBlockIndentLen() + indent.groupIndentLen = 0 + } + + override fun buildChildren(): MutableList { + val blocks = mutableListOf() + var child = node.firstChildNode + while (child != null) { + if (child !is PsiWhiteSpace) { + val block = getBlock(child) + blocks.add(block) + } + child = child.treeNext + } + return blocks + } + + override fun getBlock(child: ASTNode): SqlBlock = + when (child.elementType) { + SqlTypes.GE, SqlTypes.LE, SqlTypes.GT, SqlTypes.LT, SqlTypes.EL_EQ, SqlTypes.EL_NE, + SqlTypes.PLUS, SqlTypes.MINUS, SqlTypes.ASTERISK, SqlTypes.SLASH, SqlTypes.AT_SIGN, + -> + SqlOperationBlock(child, wrap, alignment, spacingBuilder) + + SqlTypes.EL_FIELD_ACCESS_EXPR -> + SqlElFieldAccessBlock( + child, + wrap, + alignment, + createFieldAccessSpacingBuilder(), + spacingBuilder, + ) + + SqlTypes.EL_STATIC_FIELD_ACCESS_EXPR -> + SqlElStaticFieldAccessBlock( + child, + wrap, + alignment, + createStaticFieldSpacingBuilder(), + spacingBuilder, + ) + + SqlTypes.EL_FUNCTION_CALL_EXPR -> + SqlElFunctionCallBlock( + child, + wrap, + alignment, + createSpacingBuilder(), + spacingBuilder, + ) + + SqlTypes.BLOCK_COMMENT_CONTENT -> + SqlBlockCommentBlock(child, wrap, alignment, spacingBuilder) + + else -> SqlUnknownBlock(child, wrap, alignment, spacingBuilder) + } + + private fun createFieldAccessSpacingBuilder(): SqlCustomSpacingBuilder = + SqlCustomSpacingBuilder() + .withSpacing( + SqlTypes.EL_PRIMARY_EXPR, + SqlTypes.DOT, + Spacing.createSpacing(0, 0, 0, false, 0), + ).withSpacing( + SqlTypes.DOT, + SqlTypes.EL_IDENTIFIER, + Spacing.createSpacing(0, 0, 0, false, 0), + ).withSpacing( + SqlTypes.EL_IDENTIFIER, + SqlTypes.DOT, + Spacing.createSpacing(0, 0, 0, false, 0), + ).withSpacing( + SqlTypes.EL_IDENTIFIER, + SqlTypes.EL_PARAMETERS, + Spacing.createSpacing(0, 0, 0, false, 0), + ) + + private fun createStaticFieldSpacingBuilder(): SqlCustomSpacingBuilder = + SqlCustomSpacingBuilder() + .withSpacing( + SqlTypes.AT_SIGN, + SqlTypes.EL_CLASS, + Spacing.createSpacing(0, 0, 0, false, 0), + ).withSpacing( + SqlTypes.AT_SIGN, + SqlTypes.EL_IDENTIFIER, + Spacing.createSpacing(0, 0, 0, false, 0), + ).withSpacing( + SqlTypes.EL_IDENTIFIER, + SqlTypes.DOT, + Spacing.createSpacing(0, 0, 0, false, 0), + ).withSpacing( + SqlTypes.EL_IDENTIFIER, + SqlTypes.EL_PARAMETERS, + Spacing.createSpacing(0, 0, 0, false, 0), + ) + + override fun getSpacing( + child1: Block?, + child2: Block, + ): Spacing? = + customSpacingBuilder?.getCustomSpacing(child1, child2) ?: spacingBuilder.getSpacing( + this, + child1, + child2, + ) + + override fun isLeaf(): Boolean = false + + override fun createBlockIndentLen(): Int { + parentBlock?.let { parent -> + if (parent is SqlSubGroupBlock) { + val parentIndentLen = parent.indent.groupIndentLen + val grand = parent.parentBlock + grand?.let { grand -> + if (grand is SqlCreateKeywordGroupBlock) { + val grandIndentLen = grand.indent.groupIndentLen + return grandIndentLen.plus(parentIndentLen).minus(1) + } + if (grand is SqlInsertKeywordGroupBlock) { + return parentIndentLen + } + if (grand is SqlColumnGroupBlock) { + val grandIndentLen = grand.indent.groupIndentLen + var prevTextLen = 1 + parent.prevChildren?.dropLast(1)?.forEach { prev -> prevTextLen = prevTextLen.plus(prev.node.text.length) } + return grandIndentLen.plus(prevTextLen).plus(1) + } + } + return parentIndentLen + } else { + var prevLen = 0 + parent.childBlocks + .filter { it.node.elementType == SqlTypes.KEYWORD } + .forEach { prev -> + prevLen = + prevLen.plus( + prev.node.text.length + .plus(1), + ) + } + return parent.indent.groupIndentLen + .plus(prevLen) + .plus(1) + } + } + return 1 + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlColumnDefinitionRawGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlColumnDefinitionRawGroupBlock.kt index 2c7f323d..28644c94 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlColumnDefinitionRawGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlColumnDefinitionRawGroupBlock.kt @@ -22,6 +22,7 @@ import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnDefinitionGroupBlock import org.domaframework.doma.intellij.psi.SqlTypes /** diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlCreateKeywordGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlCreateKeywordGroupBlock.kt similarity index 97% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlCreateKeywordGroupBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlCreateKeywordGroupBlock.kt index 81744982..6c7d6d68 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlCreateKeywordGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlCreateKeywordGroupBlock.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block.group +package org.domaframework.doma.intellij.formatter.block.group.keyword import com.intellij.formatting.Alignment import com.intellij.formatting.Indent diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlInlineGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInlineGroupBlock.kt similarity index 93% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlInlineGroupBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInlineGroupBlock.kt index c3ab0844..e966ac21 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlInlineGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInlineGroupBlock.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block.group +package org.domaframework.doma.intellij.formatter.block.group.keyword import com.intellij.formatting.Alignment import com.intellij.formatting.Indent @@ -23,6 +23,7 @@ import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock open class SqlInlineGroupBlock( node: ASTNode, diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlInlineSecondGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInlineSecondGroupBlock.kt similarity index 93% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlInlineSecondGroupBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInlineSecondGroupBlock.kt index de0986b9..b45a817d 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlInlineSecondGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInlineSecondGroupBlock.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block.group +package org.domaframework.doma.intellij.formatter.block.group.keyword import com.intellij.formatting.Alignment import com.intellij.formatting.Indent @@ -23,6 +23,7 @@ import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock open class SqlInlineSecondGroupBlock( node: ASTNode, diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlInsertKeywordGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInsertKeywordGroupBlock.kt similarity index 96% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlInsertKeywordGroupBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInsertKeywordGroupBlock.kt index 720d4a1e..91d80e1b 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlInsertKeywordGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInsertKeywordGroupBlock.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block.group +package org.domaframework.doma.intellij.formatter.block.group.keyword import com.intellij.formatting.Alignment import com.intellij.formatting.Indent diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlJoinGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlJoinGroupBlock.kt similarity index 89% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlJoinGroupBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlJoinGroupBlock.kt index 31c806d0..73487f11 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlJoinGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlJoinGroupBlock.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block.group +package org.domaframework.doma.intellij.formatter.block.group.keyword import com.intellij.formatting.Alignment import com.intellij.formatting.Indent @@ -55,5 +55,9 @@ open class SqlJoinGroupBlock( override fun getIndent(): Indent? = Indent.getSpaceIndent(indent.indentLen) - override fun createBlockIndentLen(): Int = parentBlock?.indent?.groupIndentLen?.plus(1) ?: 1 + override fun createBlockIndentLen(): Int = + parentBlock + ?.indent + ?.groupIndentLen + ?.plus(1) ?: 1 } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlKeywordGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt similarity index 92% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlKeywordGroupBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt index 3c34cf51..ca4d9097 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlKeywordGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block.group +package org.domaframework.doma.intellij.formatter.block.group.keyword import com.intellij.formatting.Alignment import com.intellij.formatting.Indent @@ -24,6 +24,10 @@ import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.SqlKeywordUtil import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlViewGroupBlock import org.domaframework.doma.intellij.psi.SqlTypes open class SqlKeywordGroupBlock( @@ -71,7 +75,8 @@ open class SqlKeywordGroupBlock( val diffPreBlockTextLen = node.text.length.minus(preChildBlock.node.text.length) return preChildBlock.indent.indentLen.minus(diffPreBlockTextLen) } else { - return preChildBlock.indent.indentLen + val diffPretextLen = node.text.length.minus(preChildBlock.node.text.length) + return preChildBlock.indent.indentLen.minus(diffPretextLen) } } else { return createBlockIndentLen() diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlUpdateKeywordGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlUpdateKeywordGroupBlock.kt new file mode 100644 index 00000000..a5d8b130 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlUpdateKeywordGroupBlock.kt @@ -0,0 +1,60 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.keyword + +import com.intellij.formatting.Alignment +import com.intellij.formatting.Indent +import com.intellij.formatting.SpacingBuilder +import com.intellij.formatting.Wrap +import com.intellij.lang.ASTNode +import com.intellij.psi.formatter.common.AbstractBlock +import org.domaframework.doma.intellij.formatter.IndentType +import org.domaframework.doma.intellij.formatter.block.SqlBlock + +open class SqlUpdateKeywordGroupBlock( + node: ASTNode, + wrap: Wrap?, + alignment: Alignment?, + spacingBuilder: SpacingBuilder, +) : SqlKeywordGroupBlock( + node, + IndentType.SECOND, + wrap, + alignment, + spacingBuilder, + ) { + override fun setParentGroupBlock(block: SqlBlock?) { + super.setParentGroupBlock(block) + indent.indentLevel = IndentType.SECOND + indent.indentLen = createBlockIndentLen() + indent.groupIndentLen = indent.indentLen.plus(node.text.length) + } + + override fun buildChildren(): MutableList = mutableListOf() + + override fun getIndent(): Indent? = Indent.getSpaceIndent(indent.indentLen) + + override fun createBlockIndentLen(): Int = + parentBlock?.let { + if (it.indent.indentLevel == IndentType.SUB) { + it.indent.groupIndentLen.plus(1) + } else { + val parentTextLen = it.node.text.length + val diffTextLen = parentTextLen.minus(node.text.length) + it.indent.indentLen.plus(diffTextLen) + } + } ?: 0 +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlColumnDefinitionGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnDefinitionGroupBlock.kt similarity index 96% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlColumnDefinitionGroupBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnDefinitionGroupBlock.kt index ff745c74..c86ab7ab 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlColumnDefinitionGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnDefinitionGroupBlock.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block.group +package org.domaframework.doma.intellij.formatter.block.group.subgroup import com.intellij.formatting.Alignment import com.intellij.formatting.Indent diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlColumnGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnGroupBlock.kt similarity index 93% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlColumnGroupBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnGroupBlock.kt index fb25feef..18e9f04e 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlColumnGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnGroupBlock.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block.group +package org.domaframework.doma.intellij.formatter.block.group.subgroup import com.intellij.formatting.Alignment import com.intellij.formatting.Indent @@ -23,6 +23,7 @@ import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock /** * Group blocks when generating columns with subqueries diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlDataTypeParamBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlDataTypeParamBlock.kt similarity index 89% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlDataTypeParamBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlDataTypeParamBlock.kt index eae5008a..fb5c6903 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlDataTypeParamBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlDataTypeParamBlock.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block.group +package org.domaframework.doma.intellij.formatter.block.group.subgroup import com.intellij.formatting.Alignment import com.intellij.formatting.SpacingBuilder @@ -23,7 +23,7 @@ import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock /** - * The parent must be [SqlColumnDefinitionRawGroupBlock] + * The parent must be [org.domaframework.doma.intellij.formatter.block.group.SqlColumnDefinitionRawGroupBlock] */ class SqlDataTypeParamBlock( node: ASTNode, diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlFunctionParamBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlFunctionParamBlock.kt new file mode 100644 index 00000000..202d8f1d --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlFunctionParamBlock.kt @@ -0,0 +1,51 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.subgroup + +import com.intellij.formatting.Alignment +import com.intellij.formatting.SpacingBuilder +import com.intellij.formatting.Wrap +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.IndentType +import org.domaframework.doma.intellij.formatter.block.SqlBlock + +class SqlFunctionParamBlock( + node: ASTNode, + wrap: Wrap?, + alignment: Alignment?, + spacingBuilder: SpacingBuilder, +) : SqlSubGroupBlock( + node, + wrap, + alignment, + spacingBuilder, + ) { + override val indent = + ElementIndent( + IndentType.PARAM, + 0, + 0, + ) + + override fun setParentGroupBlock(block: SqlBlock?) { + super.setParentGroupBlock(block) + indent.indentLevel = IndentType.PARAM + indent.indentLen = 0 + indent.groupIndentLen = 0 + } + + override fun createBlockIndentLen(): Int = 0 +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlInsertColumnGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlInsertColumnGroupBlock.kt similarity index 94% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlInsertColumnGroupBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlInsertColumnGroupBlock.kt index 044cb549..b9e05849 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlInsertColumnGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlInsertColumnGroupBlock.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block.group +package org.domaframework.doma.intellij.formatter.block.group.subgroup import com.intellij.formatting.Alignment import com.intellij.formatting.Indent @@ -22,6 +22,7 @@ import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInsertKeywordGroupBlock import org.domaframework.doma.intellij.psi.SqlTypes /** diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlParallelListBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlParallelListBlock.kt new file mode 100644 index 00000000..ed7634df --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlParallelListBlock.kt @@ -0,0 +1,52 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.subgroup + +import com.intellij.formatting.Alignment +import com.intellij.formatting.SpacingBuilder +import com.intellij.formatting.Wrap +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.IndentType +import org.domaframework.doma.intellij.formatter.block.SqlBlock + +/** + * A class that represents the List type test data after the IN clause. + * If the child element is a [org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock], + * it controls the indentation in the same way as a [SqlSubQueryGroupBlock]. + * If the direct child element is a comma, it controls the line break. + */ +class SqlParallelListBlock( + node: ASTNode, + wrap: Wrap?, + alignment: Alignment?, + spacingBuilder: SpacingBuilder, +) : SqlSubQueryGroupBlock( + node, + wrap, + alignment, + spacingBuilder, + ) { + override val indent = + ElementIndent( + IndentType.SUB, + 0, + 0, + ) + + override fun setParentGroupBlock(block: SqlBlock?) { + super.setParentGroupBlock(block) + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlSubGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt similarity index 93% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlSubGroupBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt index 2c1a664b..928bd9e7 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlSubGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block.group +package org.domaframework.doma.intellij.formatter.block.group.subgroup import com.intellij.formatting.Alignment import com.intellij.formatting.Indent @@ -24,6 +24,7 @@ import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlCommentBlock +import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock abstract class SqlSubGroupBlock( node: ASTNode, diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlSubQueryGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt similarity index 93% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlSubQueryGroupBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt index 2a737edc..dd09087d 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlSubQueryGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block.group +package org.domaframework.doma.intellij.formatter.block.group.subgroup import com.intellij.formatting.Alignment import com.intellij.formatting.Indent @@ -23,9 +23,10 @@ import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlJoinGroupBlock import org.domaframework.doma.intellij.psi.SqlTypes -class SqlSubQueryGroupBlock( +open class SqlSubQueryGroupBlock( node: ASTNode, wrap: Wrap?, alignment: Alignment?, diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlUpdateColumnGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlUpdateColumnGroupBlock.kt new file mode 100644 index 00000000..d9d37443 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlUpdateColumnGroupBlock.kt @@ -0,0 +1,89 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.subgroup + +import com.intellij.formatting.Alignment +import com.intellij.formatting.Indent +import com.intellij.formatting.SpacingBuilder +import com.intellij.formatting.Wrap +import com.intellij.lang.ASTNode +import com.intellij.psi.formatter.common.AbstractBlock +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlUpdateKeywordGroupBlock +import org.domaframework.doma.intellij.psi.SqlTypes + +/** + * In an UPDATE statement using the row value constructor, + * a group representing the column list + */ +class SqlUpdateColumnGroupBlock( + node: ASTNode, + wrap: Wrap?, + alignment: Alignment?, + spacingBuilder: SpacingBuilder, +) : SqlSubGroupBlock( + node, + wrap, + alignment, + spacingBuilder, + ) { + override fun setParentGroupBlock(block: SqlBlock?) { + super.setParentGroupBlock(block) + indent.indentLen = createBlockIndentLen() + indent.groupIndentLen = indent.indentLen.plus(1) + updateParentGroupIndentLen() + } + + override fun buildChildren(): MutableList = mutableListOf() + + override fun getIndent(): Indent? = Indent.getSpaceIndent(indent.indentLen) + + override fun createBlockIndentLen(): Int { + parentBlock?.let { + if (it is SqlUpdateKeywordGroupBlock) { + var parentLen = 0 + val keywords = + it.childBlocks.dropLast(1).takeWhile { it.node.elementType == SqlTypes.KEYWORD } + keywords.forEach { keyword -> + parentLen = parentLen.plus(keyword.node.text.length).plus(1) + } + return it.indent.indentLen + .plus(it.node.text.length) + .plus(1) + .plus(parentLen) + } + // TODO:Customize indentation + return 2 + } ?: return 2 + } + + private fun updateParentGroupIndentLen() { + parentBlock?.let { + if (it is SqlUpdateKeywordGroupBlock) { + var parentLen = 0 + val keywords = + it.childBlocks.dropLast(1).takeWhile { it.node.elementType == SqlTypes.KEYWORD } + keywords.forEach { keyword -> + parentLen = parentLen.plus(keyword.node.text.length).plus(1) + } + it.indent.groupIndentLen = + it.indent.indentLen + .plus(it.node.text.length) + .plus(parentLen) + } + } + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlUpdateValueGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlUpdateValueGroupBlock.kt new file mode 100644 index 00000000..74e8ef44 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlUpdateValueGroupBlock.kt @@ -0,0 +1,78 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.subgroup + +import com.intellij.formatting.Alignment +import com.intellij.formatting.Indent +import com.intellij.formatting.SpacingBuilder +import com.intellij.formatting.Wrap +import com.intellij.lang.ASTNode +import com.intellij.psi.formatter.common.AbstractBlock +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlUpdateKeywordGroupBlock +import org.domaframework.doma.intellij.psi.SqlTypes + +/** + * In an UPDATE statement using the row value constructor, + * a group representing the value list + */ +class SqlUpdateValueGroupBlock( + node: ASTNode, + wrap: Wrap?, + alignment: Alignment?, + spacingBuilder: SpacingBuilder, +) : SqlSubGroupBlock( + node, + wrap, + alignment, + spacingBuilder, + ) { + override fun setParentGroupBlock(block: SqlBlock?) { + super.setParentGroupBlock(block) + indent.indentLen = createBlockIndentLen() + indent.groupIndentLen = createGroupIndentLen() + } + + override fun buildChildren(): MutableList = mutableListOf() + + override fun getIndent(): Indent? = Indent.getSpaceIndent(indent.indentLen) + + override fun createBlockIndentLen(): Int { + parentBlock?.let { parent -> + if (parent is SqlUpdateKeywordGroupBlock) { + val keywords = + parent.childBlocks + .dropLast(1) + .takeWhile { parent.node.elementType == SqlTypes.KEYWORD } + return parent.indent.indentLen + .plus(parent.node.text.length) + .plus(3) + } + // TODO:Customize indentation + return 2 + } ?: return 2 + } + + private fun createGroupIndentLen(): Int { + parentBlock?.let { parent -> + if (parent is SqlUpdateKeywordGroupBlock) { + val parentGroupIndent = parent.indent.groupIndentLen + return parentGroupIndent.plus(4) + } + } ?: return 2 + return 2 + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlViewGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlViewGroupBlock.kt similarity index 92% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlViewGroupBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlViewGroupBlock.kt index b878947e..5a42379c 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlViewGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlViewGroupBlock.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block.group +package org.domaframework.doma.intellij.formatter.block.group.subgroup import com.intellij.formatting.Alignment import com.intellij.formatting.Indent @@ -23,6 +23,7 @@ import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock open class SqlViewGroupBlock( node: ASTNode, diff --git a/src/main/kotlin/org/domaframework/doma/intellij/gutter/sql/SqlLineMakerProvider.kt b/src/main/kotlin/org/domaframework/doma/intellij/gutter/sql/SqlLineMakerProvider.kt index 3c5039c6..05c6b13b 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/gutter/sql/SqlLineMakerProvider.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/gutter/sql/SqlLineMakerProvider.kt @@ -47,7 +47,7 @@ class SqlLineMakerProvider : RelatedItemLineMarkerProvider() { val file = e.containingFile ?: return if (!isSupportFileType(file) || isInjectionSqlFile(file)) return // Display only on the first line - if (e.originalElement.parent.originalElement !is PsiFile || + if (e.originalElement?.parent?.originalElement !is PsiFile || e.textRange.startOffset != file.textRange.startOffset ) { return diff --git a/src/test/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatterTest.kt b/src/test/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatterTest.kt index c4f60b49..82c49e86 100644 --- a/src/test/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatterTest.kt +++ b/src/test/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatterTest.kt @@ -57,6 +57,22 @@ class SqlFormatterTest : BasePlatformTestCase() { formatSqlFime("Insert.sql", "FormattedInsert.sql") } + fun testInsertWithBindVariableFormatter() { + formatSqlFime("InsertWithBindVariable.sql", "FormattedInsertWithBindVariable.sql") + } + + fun testUpdateFormatter() { + formatSqlFime("Update.sql", "FormattedUpdate.sql") + } + + fun testUpdateBindVariableFormatter() { + formatSqlFime("UpdateBindVariable.sql", "FormattedUpdateBindVariable.sql") + } + + fun testUpdateTupleAssignmentFormatter() { + formatSqlFime("UpdateTupleAssignment.sql", "FormattedUpdateTupleAssignment.sql") + } + fun testDeleteFormatter() { formatSqlFime("Delete.sql", "FormattedDelete.sql") } diff --git a/src/test/testData/sql/formatter/FormattedInsertWithBindVariable.sql b/src/test/testData/sql/formatter/FormattedInsertWithBindVariable.sql new file mode 100644 index 00000000..3f06b1bb --- /dev/null +++ b/src/test/testData/sql/formatter/FormattedInsertWithBindVariable.sql @@ -0,0 +1,19 @@ +INSERT INTO /*# tableName */ + (x1 + , x2 + /*%for entity : entities */ + , /*# entity.itemIdentifier */ + /*%end*/ + , x3 + , x4) + VALUES ( /* reportId */1 + , /* @tenantId() */1 + /*%for entity : entities */ + , /* entity.value */'abc' + /*%end*/ + , /* @userId() */1 + , x5 + , /* @userId() */1 + , x6 + , 1 + , /* @maxDateTime() */'9999-12-31') diff --git a/src/test/testData/sql/formatter/FormattedSelect.sql b/src/test/testData/sql/formatter/FormattedSelect.sql index 7c252b06..78ce90f7 100644 --- a/src/test/testData/sql/formatter/FormattedSelect.sql +++ b/src/test/testData/sql/formatter/FormattedSelect.sql @@ -1,5 +1,6 @@ /** TopBlock */ -SELECT o.* +SELECT COUNT(DISTINCT (x)) + , o.* , ISNULL(nbor.nearest , 999) AS nearest -- column Line comment /** From */ @@ -20,6 +21,7 @@ SELECT o.* LEFT OUTER JOIN specobj s /** ON */ ON p.objid = s.bestobjid + AND p.plate = s.plate /** Where */ WHERE p.TYPE = DBO.FPHOTOTYPE('Star') AND (p.flags & DBO.FPHOTOFLAGS('EDGE')) = 0 @@ -40,4 +42,5 @@ SELECT o.* OR x.TYPE = DBO.FPHOTOTYPE('Galaxy')) AND x.modelmag_g BETWEEN 10 AND 21 GROUP BY n.objid ) AS nbor - ON o.objid = nbor.objid + ON o.objid = nbor.objid + WHERE p.list IN /* params */(1, 2, 3) diff --git a/src/test/testData/sql/formatter/FormattedUpdate.sql b/src/test/testData/sql/formatter/FormattedUpdate.sql index 5fea96fe..d1e262d6 100644 --- a/src/test/testData/sql/formatter/FormattedUpdate.sql +++ b/src/test/testData/sql/formatter/FormattedUpdate.sql @@ -1,4 +1,4 @@ -UPDATE USER +UPDATE user SET name = /* user.name */'name' , rank = /*user.rank */3 WHERE id = /* user.id */1 diff --git a/src/test/testData/sql/formatter/FormattedUpdateBindVariable.sql b/src/test/testData/sql/formatter/FormattedUpdateBindVariable.sql new file mode 100644 index 00000000..d5fd4d4b --- /dev/null +++ b/src/test/testData/sql/formatter/FormattedUpdateBindVariable.sql @@ -0,0 +1,8 @@ +UPDATE /*# tableName */ + SET X1 = 1 + , X2 = 2 + , X3 = 3 + /*%for entity : entities */ + , /*# entity.itemIdentifier */= /* entity.value */'abc' + /*%end*/ + WHERE X = /* reportId */1 diff --git a/src/test/testData/sql/formatter/FormattedUpdateTupleAssignment.sql b/src/test/testData/sql/formatter/FormattedUpdateTupleAssignment.sql new file mode 100644 index 00000000..84ccc55e --- /dev/null +++ b/src/test/testData/sql/formatter/FormattedUpdateTupleAssignment.sql @@ -0,0 +1,16 @@ +UPDATE /*# tableName */ + SET (x1 + , x2 + , x3 + /*%for entity : entities */ + , /*# entity.itemIdentifier */ + /*%end*/ + ) + = ( /* @userId() */1 + , x + , x + 1 + /*%for entity : entities */ + , /* entity.value */'abc' + /*%end*/ + ) + WHERE x = /* reportId */1 diff --git a/src/test/testData/sql/formatter/InsertWithBindVariable.sql b/src/test/testData/sql/formatter/InsertWithBindVariable.sql new file mode 100644 index 00000000..9f5b2726 --- /dev/null +++ b/src/test/testData/sql/formatter/InsertWithBindVariable.sql @@ -0,0 +1,16 @@ +INSERT INTO /*# tableName */ + (x1 + , x2 + /*%for entity : entities */ + , /*# entity.itemIdentifier */ + /*%end*/ + , x3 + , x4) + VALUES ( /* reportId */1, /* @tenantId() */1 /*%for entity : entities */, /* entity.value */'abc' + /*%end*/ + , /* @userId() */1 + , x5 + , /* @userId() */1 + , x6 + , 1 + , /* @maxDateTime() */'9999-12-31') diff --git a/src/test/testData/sql/formatter/Select.sql b/src/test/testData/sql/formatter/Select.sql index 1084a0f3..d505db2b 100644 --- a/src/test/testData/sql/formatter/Select.sql +++ b/src/test/testData/sql/formatter/Select.sql @@ -1,5 +1,5 @@ /** TopBlock */ -SELECT o.* +SELECT COUNT( DISTINCT (x)),o.* , ISNULL(nbor.nearest , 999) AS nearest -- column Line comment /** From */ @@ -22,7 +22,7 @@ SELECT o.* /** Join */ LEFT OUTER JOIN specobj s /** ON */ - ON p.objid = s.bestobjid + ON p.objid = s.bestobjid AND p.plate = s.plate /** Where */ WHERE p.TYPE = DBO.FPHOTOTYPE('Star') AND (p.flags & DBO.FPHOTOFLAGS('EDGE')) = 0 @@ -51,4 +51,7 @@ SELECT o.* AND x.modelmag_g BETWEEN 10 AND 21 GROUP BY n.objid ) AS nbor - ON o.objid = nbor.objid \ No newline at end of file + ON o.objid = nbor.objid + WHERE p.list IN /* params */(1 + ,2 + ,3) \ No newline at end of file diff --git a/src/test/testData/sql/formatter/UpdateBindVariable.sql b/src/test/testData/sql/formatter/UpdateBindVariable.sql new file mode 100644 index 00000000..865d2de6 --- /dev/null +++ b/src/test/testData/sql/formatter/UpdateBindVariable.sql @@ -0,0 +1,8 @@ +UPDATE /*# tableName */ + SET X1 = 1 + , X2 = 2 + , X3 = 3 + /*%for entity : entities */ + , /*# entity.itemIdentifier */= /* entity.value */'abc' + /*%end*/ + WHERE X = /* reportId */1 \ No newline at end of file diff --git a/src/test/testData/sql/formatter/UpdateTupleAssignment.sql b/src/test/testData/sql/formatter/UpdateTupleAssignment.sql new file mode 100644 index 00000000..15d8a5c4 --- /dev/null +++ b/src/test/testData/sql/formatter/UpdateTupleAssignment.sql @@ -0,0 +1,12 @@ +UPDATE /*# tableName */ + SET (x1 + , x2 + , x3 + /*%for entity : entities */ + , /*# entity.itemIdentifier */ + /*%end*/) = ( /* @userId() */1 + , x + , x + 1 + /*%for entity : entities */ + , /* entity.value */'abc' + /*%end*/) WHERE x = /* reportId */1