From 3037f584a4af1a11b3556ba466bb793a1b691c0e Mon Sep 17 00:00:00 2001 From: xterao Date: Thu, 17 Jul 2025 13:06:39 +0900 Subject: [PATCH 01/11] Enhance SQL formatting for condition and loop directives with improved indentation handling --- .../doma/intellij/formatter/block/SqlBlock.kt | 10 +- .../intellij/formatter/block/SqlFileBlock.kt | 15 ++- .../formatter/block/SqlRightPatternBlock.kt | 11 +- .../block/comment/SqlLineCommentBlock.kt | 7 ++ .../block/expr/SqlElBlockCommentBlock.kt | 74 ++++++++++-- .../expr/SqlElConditionLoopCommentBlock.kt | 109 +++++++++++++++--- .../block/group/keyword/SqlJoinGroupBlock.kt | 14 ++- .../group/keyword/SqlKeywordGroupBlock.kt | 52 +++++---- .../group/keyword/SqlLateralGroupBlock.kt | 2 + .../SqlSecondOptionKeywordGroupBlock.kt | 2 + .../SqlConditionKeywordGroupBlock.kt | 5 +- .../keyword/second/SqlSecondKeywordBlock.kt | 3 + .../keyword/top/SqlJoinQueriesGroupBlock.kt | 8 +- .../keyword/top/SqlTopQueryGroupBlock.kt | 17 ++- .../group/subgroup/SqlDataTypeParamBlock.kt | 2 - .../group/subgroup/SqlFunctionParamBlock.kt | 46 ++++---- .../block/group/subgroup/SqlSubGroupBlock.kt | 8 +- .../group/subgroup/SqlSubQueryGroupBlock.kt | 34 +++--- .../formatter/block/word/SqlWordBlock.kt | 5 + .../formatter/builder/SqlBlockBuilder.kt | 108 ++++++++++++++--- .../builder/SqlCustomSpacingBuilder.kt | 30 +++-- .../processor/SqlSetParentGroupProcessor.kt | 77 +++++++++---- 22 files changed, 481 insertions(+), 158 deletions(-) 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 5e9978b8..4615d336 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 @@ -26,6 +26,7 @@ import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.psi.SqlTypes @@ -114,7 +115,14 @@ open class SqlBlock( fun isEnableFormat(): Boolean = enableFormat - open fun isSaveSpace(lastGroup: SqlBlock?): Boolean = false + open fun isSaveSpace(lastGroup: SqlBlock?): Boolean = + parentBlock?.let { parent -> + if (parent is SqlElConditionLoopCommentBlock) { + parent.childBlocks.dropLast(1).isEmpty() + } else { + false + } + } == true /** * Creates the indentation length for the block. diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt index 3b3cef03..377b7f80 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt @@ -26,6 +26,7 @@ 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.common.util.TypeUtil import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock @@ -440,6 +441,15 @@ class SqlFileBlock( return SqlCustomSpacingBuilder().getSpacing(childBlock2) } + if (childBlock1 is SqlWhitespaceBlock && childBlock2.parentBlock is SqlElConditionLoopCommentBlock) { + val child1 = childBlock2.parentBlock as SqlElConditionLoopCommentBlock + SqlCustomSpacingBuilder().getSpacingElDirectiveComment(child1, childBlock2)?.let { return it } + } + + if (childBlock1 is SqlElBlockCommentBlock) { + SqlCustomSpacingBuilder().getSpacingElDirectiveComment(childBlock1, childBlock2)?.let { return it } + } + if (childBlock2 is SqlWithColumnGroupBlock) { return SqlCustomSpacingBuilder.normalSpacing } @@ -454,8 +464,11 @@ class SqlFileBlock( } if (childBlock2 is SqlElBlockCommentBlock) { + if (TypeUtil.isExpectedClassType(SqlRightPatternBlock.NOT_INSERT_SPACE_TYPES, childBlock1)) { + return SqlCustomSpacingBuilder.nonSpacing + } return when (childBlock1) { - is SqlElBlockCommentBlock, is SqlWhitespaceBlock -> { + is SqlWhitespaceBlock -> { SqlCustomSpacingBuilder().getSpacing(childBlock2) } 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 2a2443ba..02126929 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 @@ -52,12 +52,13 @@ open class SqlRightPatternBlock( var preSpaceRight = false companion object { - private val NOT_INSERT_SPACE_TYPES = + val NOT_INSERT_SPACE_TYPES = listOf( SqlFunctionParamBlock::class, SqlInsertColumnGroupBlock::class, SqlWithQuerySubGroupBlock::class, SqlConflictExpressionSubGroupBlock::class, + SqlConditionalExpressionGroupBlock::class, ) private val INDENT_EXPECTED_TYPES = @@ -67,7 +68,7 @@ open class SqlRightPatternBlock( SqlCreateTableColumnDefinitionGroupBlock::class, ) - private val NEW_LINE_EXPECTED_TYPES = + val NEW_LINE_EXPECTED_TYPES = listOf( SqlUpdateColumnGroupBlock::class, SqlUpdateValueGroupBlock::class, @@ -96,6 +97,10 @@ open class SqlRightPatternBlock( preSpaceRight = false return } + if (isExpectedClassType(INDENT_EXPECTED_TYPES, parent)) { + preSpaceRight = true + return + } // Check if parent is SqlSubQueryGroupBlock if (parent is SqlSubQueryGroupBlock) { @@ -144,8 +149,6 @@ open class SqlRightPatternBlock( if (preSpaceRight) return 1 parentBlock?.let { parent -> - if (parent is SqlWithQuerySubGroupBlock) return 0 - if (isExpectedClassType(INDENT_EXPECTED_TYPES, parent)) return parent.indent.indentLen return parent.indent.indentLen } ?: return 0 } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlLineCommentBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlLineCommentBlock.kt index adbcc527..d0f0d0d6 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlLineCommentBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlLineCommentBlock.kt @@ -39,6 +39,13 @@ open class SqlLineCommentBlock( override fun isLeaf(): Boolean = true override fun createBlockIndentLen(): Int { + val prevElement = PsiTreeUtil.prevLeaf(node.psi, false) + if (prevElement?.text?.contains("\n") != true && + prevElement != null && + PsiTreeUtil.prevLeaf(prevElement) !is SqlLineCommentBlock + ) { + return 1 + } parentBlock?.let { parent -> if (parent is SqlSubQueryGroupBlock) { if (parent.getChildBlocksDropLast().isEmpty()) { 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 9977ef98..ec180bdd 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 @@ -20,6 +20,8 @@ import com.intellij.formatting.Spacing import com.intellij.lang.ASTNode import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.formatter.common.AbstractBlock +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.psi.util.elementType import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlOperationBlock import org.domaframework.doma.intellij.formatter.block.SqlUnknownBlock @@ -30,6 +32,9 @@ import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQuer import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext +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.SqlTypes open class SqlElBlockCommentBlock( @@ -37,6 +42,17 @@ open class SqlElBlockCommentBlock( private val context: SqlBlockFormattingContext, open val customSpacingBuilder: SqlCustomSpacingBuilder?, ) : SqlCommentBlock(node, context) { + enum class SqlElCommentDirectiveType { + CONDITION_LOOP, + EXPAND, + POPULATE, + LITERAL, + EMBEDDED, + NORMAL, + } + + val directiveType: SqlElCommentDirectiveType = initDirectiveType() + override val indent = ElementIndent( IndentType.NONE, @@ -51,6 +67,34 @@ open class SqlElBlockCommentBlock( indent.groupIndentLen = 0 } + private fun initDirectiveType(): SqlElCommentDirectiveType { + val element = this.node.psi + val contentElement = PsiTreeUtil.firstChild(element).nextSibling + + if (contentElement is SqlElIfDirective || + contentElement is SqlElForDirective || + contentElement is SqlElElseifDirective || + contentElement.elementType == SqlTypes.EL_ELSE || + contentElement.elementType == SqlTypes.EL_END + ) { + return SqlElCommentDirectiveType.CONDITION_LOOP + } + if (contentElement.elementType == SqlTypes.HASH) { + return SqlElCommentDirectiveType.EMBEDDED + } + if (contentElement.elementType == SqlTypes.EL_EXPAND) { + return SqlElCommentDirectiveType.EXPAND + } + if (contentElement.elementType == SqlTypes.EL_POPULATE) { + return SqlElCommentDirectiveType.POPULATE + } + if (contentElement.elementType == SqlTypes.CARET) { + return SqlElCommentDirectiveType.LITERAL + } + + return SqlElCommentDirectiveType.NORMAL + } + override fun buildChildren(): MutableList { val blocks = mutableListOf() var child = node.firstChildNode @@ -130,20 +174,30 @@ open class SqlElBlockCommentBlock( override fun createBlockIndentLen(): Int { parentBlock?.let { parent -> - if (parent is SqlSubQueryGroupBlock) { - if (parent.getChildBlocksDropLast().isEmpty()) { - return 0 + return when (parent) { + is SqlElConditionLoopCommentBlock -> parent.indent.groupIndentLen + is SqlSubQueryGroupBlock -> { + if (parent.getChildBlocksDropLast().isEmpty()) { + 0 + } else if (parent.isFirstLineComment) { + parent.indent.groupIndentLen.minus(2) + } else { + parent.indent.groupIndentLen + } } - if (parent.isFirstLineComment) { - return parent.indent.groupIndentLen.minus(2) - } - } - if (parent is SqlValuesGroupBlock) { - return parent.indent.indentLen + is SqlValuesGroupBlock -> parent.indent.indentLen + else -> parent.indent.groupIndentLen } } return 0 } - override fun isSaveSpace(lastGroup: SqlBlock?): Boolean = parentBlock is SqlValuesGroupBlock + override fun isSaveSpace(lastGroup: SqlBlock?): Boolean = + parentBlock?.let { parent -> + ( + parent is SqlValuesGroupBlock || + parent is SqlElConditionLoopCommentBlock + ) && + parent.childBlocks.dropLast(1).isEmpty() + } == true } 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 index 931231ef..d14edbcf 100644 --- 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 @@ -22,12 +22,15 @@ import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.formatter.common.AbstractBlock import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.elementType +import org.domaframework.doma.intellij.common.util.TypeUtil import org.domaframework.doma.intellij.extension.expr.isConditionOrLoopDirective import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlCommaBlock import org.domaframework.doma.intellij.formatter.block.SqlOperationBlock +import org.domaframework.doma.intellij.formatter.block.SqlRightPatternBlock import org.domaframework.doma.intellij.formatter.block.SqlUnknownBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnRawGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateKeywordGroupBlock @@ -52,6 +55,7 @@ class SqlElConditionLoopCommentBlock( ) { enum class SqlConditionLoopCommentBlockType { CONDITION, + ELSE, LOOP, END, UNKNOWN, @@ -59,10 +63,14 @@ class SqlElConditionLoopCommentBlock( fun isEnd(): Boolean = this == END - fun isInvalid(): Boolean = this == UNKNOWN + fun isStartDirective(): Boolean = this == CONDITION || this == LOOP + + fun isElse(): Boolean = this == ELSE } val conditionType: SqlConditionLoopCommentBlockType = initConditionOrLoopType(node) + var conditionStart: SqlElConditionLoopCommentBlock? = null + var conditionEnd: SqlElConditionLoopCommentBlock? = null private fun initConditionOrLoopType(node: ASTNode): SqlConditionLoopCommentBlockType { val psi = node.psi @@ -70,12 +78,16 @@ class SqlElConditionLoopCommentBlock( if (PsiTreeUtil.getChildOfType(psi, SqlElForDirective::class.java) != null) { return SqlConditionLoopCommentBlockType.LOOP } - if (PsiTreeUtil.getChildOfType(psi, SqlElIfDirective::class.java) != null || - psi.findElementAt(2)?.elementType == SqlTypes.EL_ELSE - ) { + val directiveElement = psi.findElementAt(2) + if (PsiTreeUtil.getChildOfType(psi, SqlElIfDirective::class.java) != null) { return SqlConditionLoopCommentBlockType.CONDITION } - if (psi.findElementAt(2)?.elementType == SqlTypes.EL_END) { + if (directiveElement?.elementType == SqlTypes.EL_ELSE || + directiveElement?.elementType == SqlTypes.EL_ELSEIF + ) { + return SqlConditionLoopCommentBlockType.ELSE + } + if (directiveElement?.elementType == SqlTypes.EL_END) { return SqlConditionLoopCommentBlockType.END } } @@ -89,11 +101,32 @@ class SqlElConditionLoopCommentBlock( 0, ) + /** + * Initially, set a **provisional indentation level** for conditional directives. + * + * If the next element is a **[SqlKeywordGroupBlock]** or **[SqlSubGroupBlock]**, align the directive’s indentation to that keyword’s indentation. + * Otherwise, use the **provisional indentation element as the base** to align the indentation of child elements under the directive. + */ override fun setParentGroupBlock(lastGroup: SqlBlock?) { super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.NONE indent.indentLen = createBlockIndentLen() - indent.groupIndentLen = 0 + indent.groupIndentLen = createGroupIndentLen() + + childBlocks.forEach { child -> + if (child is SqlElConditionLoopCommentBlock) { + // If the child is a condition loop directive, align its indentation with the parent directive + child.indent.indentLen = indent.indentLen.plus(2) + } else if (child is SqlLineCommentBlock) { + if (PsiTreeUtil.prevLeaf(child.node.psi, false)?.text?.contains("\n") == true) { + child.indent.indentLen = indent.groupIndentLen + } else { + child.indent.indentLen = 1 + } + } else { + child.indent.indentLen = indent.groupIndentLen + } + } } override fun buildChildren(): MutableList { @@ -173,11 +206,31 @@ class SqlElConditionLoopCommentBlock( override fun isLeaf(): Boolean = false - override fun isSaveSpace(lastGroup: SqlBlock?): Boolean = true + override fun isSaveSpace(lastGroup: SqlBlock?): Boolean { + if (lastGroup is SqlSubGroupBlock) { + return lastGroup.childBlocks.dropLast(1).isNotEmpty() + } + return true + } + /** + * If the element directly under the directive is [SqlKeywordGroupBlock] or [SqlSubGroupBlock], + * make it the parent and align the indentation with the group directly under it. + * + * If the element immediately below the directive is not [SqlKeywordGroupBlock] or [SqlSubGroupBlock], + * align it to the previous group indent. + */ override fun createBlockIndentLen(): Int { parentBlock?.let { parent -> + if (conditionType.isEnd() || conditionType.isElse()) { + return parent.indent.indentLen + } + val openConditionLoopDirectiveCount = getOpenDirectiveCount(parent) when (parent) { + is SqlKeywordGroupBlock, is SqlCommaBlock -> { + return parent.indent.indentLen.plus(openConditionLoopDirectiveCount * 2) + } + is SqlSubGroupBlock -> { val parentGroupIndentLen = parent.indent.groupIndentLen val grand = parent.parentBlock @@ -195,22 +248,48 @@ class SqlElConditionLoopCommentBlock( parent.prevChildren?.dropLast(1)?.forEach { prev -> prevTextLen = prevTextLen.plus(prev.getNodeText().length) } - return grandIndentLen.plus(prevTextLen).plus(1) + return grandIndentLen.plus(prevTextLen) } } - return parentGroupIndentLen - } - - is SqlKeywordGroupBlock, is SqlCommaBlock -> { - return parent.indent.indentLen + return if (TypeUtil.isExpectedClassType( + SqlRightPatternBlock.NOT_INSERT_SPACE_TYPES, + parent, + ) + ) { + parentGroupIndentLen.plus(openConditionLoopDirectiveCount * 2) + } else { + parentGroupIndentLen.plus(openConditionLoopDirectiveCount * 2).plus(1) + } } - // Parent of End Block is SqlElConditionLoopCommentBlock is SqlElConditionLoopCommentBlock -> { - return parent.indent.indentLen + if (conditionType.isEnd()) { + parent.conditionEnd = this + conditionStart = parent + return parent.indent.indentLen + } else if (conditionType.isElse()) { + return parent.indent.indentLen + } else { + return parent.indent.indentLen.plus(2) + } } } } return 0 } + + override fun createGroupIndentLen(): Int = indent.indentLen + + private fun getOpenDirectiveCount(parent: SqlBlock): Int { + val conditionLoopDirectives: List = + parent + .childBlocks + .mapNotNull { it as? SqlElConditionLoopCommentBlock } + .filter { it.conditionEnd == null } + val startDirectives = + conditionLoopDirectives.count { it.conditionType.isStartDirective() } + val endDirectives = conditionLoopDirectives.count { it.conditionType.isEnd() } + val diffCount = startDirectives.minus(endDirectives) + return if (diffCount > 0) diffCount.minus(1) else 0 + } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlJoinGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlJoinGroupBlock.kt index d33159eb..51f38dd2 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlJoinGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlJoinGroupBlock.kt @@ -18,6 +18,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword 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.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext @@ -46,11 +47,14 @@ open class SqlJoinGroupBlock( override fun buildChildren(): MutableList = mutableListOf() - override fun createBlockIndentLen(): Int = - parentBlock - ?.indent - ?.groupIndentLen - ?.plus(1) ?: 1 + override fun createBlockIndentLen(): Int { + return parentBlock?.let { parent -> + if (parent is SqlElConditionLoopCommentBlock) { + return parent.indent.groupIndentLen + } + return parent.indent.groupIndentLen.plus(1) + } ?: 1 + } override fun createGroupIndentLen(): Int = indent.indentLen diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt index ad12c13e..bb759e5c 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt @@ -20,6 +20,7 @@ import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.common.util.TypeUtil import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.top.SqlSelectQueryGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithCommonTableGroupBlock @@ -115,15 +116,17 @@ open class SqlKeywordGroupBlock( open fun adjustIndentIfFirstChildIsLineComment(baseIndent: Int): Int { parentBlock?.let { parent -> if (indent.indentLevel == IndentType.TOP) { - return if (parent is SqlSubGroupBlock) { - return if (parent.isFirstLineComment) { - parent.indent.groupIndentLen.minus(parent.getNodeText().length) - } else { - val newIndentLen = baseIndent.minus(1) - return if (newIndentLen >= 0) newIndentLen else 0 + when (parent) { + is SqlSubGroupBlock -> { + return if (parent.isFirstLineComment) { + parent.indent.groupIndentLen.minus(parent.getNodeText().length) + } else { + val newIndentLen = baseIndent.minus(1) + return if (newIndentLen >= 0) newIndentLen else 0 + } } - } else { - return baseIndent + + else -> return baseIndent } } } @@ -131,10 +134,15 @@ open class SqlKeywordGroupBlock( } open fun createBlockIndentLen(preChildBlock: SqlBlock?): Int { - when (indentLevel) { - IndentType.TOP -> { - parentBlock?.let { parent -> - if (SqlKeywordUtil.isSetLineKeyword(getNodeText(), preChildBlock?.getNodeText() ?: "")) { + parentBlock?.let { parent -> + if (parent is SqlElConditionLoopCommentBlock) return parent.indent.groupIndentLen + when (indentLevel) { + IndentType.TOP -> { + if (SqlKeywordUtil.isSetLineKeyword( + getNodeText(), + preChildBlock?.getNodeText() ?: "", + ) + ) { val prevBlockIndent = preChildBlock?.indent?.indentLen ?: 0 val prevBlockLen = preChildBlock?.getNodeText()?.length ?: 0 return prevBlockIndent.plus(prevBlockLen).plus(1) @@ -144,20 +152,18 @@ open class SqlKeywordGroupBlock( } else { parent.indent.groupIndentLen } - } ?: return 0 - } + } - IndentType.INLINE_SECOND -> { - parentBlock?.let { - if (it.indent.indentLevel == IndentType.FILE) 0 - return it.indent.groupIndentLen + IndentType.INLINE_SECOND -> { + if (parent.indent.indentLevel == IndentType.FILE) 0 + return parent.indent.groupIndentLen .plus(1) - } ?: return 1 - } + } - else -> return 1 - } - return 1 + else -> return 1 + } + return 1 + } ?: return 1 } override fun createGroupIndentLen(): Int = indent.indentLen.plus(topKeywordBlocks.sumOf { it.getNodeText().length.plus(1) }.minus(1)) diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlLateralGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlLateralGroupBlock.kt index dc742f83..29da9958 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlLateralGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlLateralGroupBlock.kt @@ -17,6 +17,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlFromGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock import org.domaframework.doma.intellij.formatter.util.IndentType @@ -46,6 +47,7 @@ class SqlLateralGroupBlock( override fun createBlockIndentLen(): Int { parentBlock?.let { parent -> + if (parent is SqlElConditionLoopCommentBlock) return parent.indent.groupIndentLen return parent.indent.groupIndentLen.plus(1) } return 0 diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlSecondOptionKeywordGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlSecondOptionKeywordGroupBlock.kt index b8f2f6b4..1c8136a7 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlSecondOptionKeywordGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlSecondOptionKeywordGroupBlock.kt @@ -18,6 +18,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock 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.util.IndentType @@ -39,6 +40,7 @@ open class SqlSecondOptionKeywordGroupBlock( if (parent.indent.indentLevel == IndentType.FILE) { return 0 } + if (parent is SqlElConditionLoopCommentBlock) return groupLen val subGroupBlock = parent.parentBlock as? SqlSubGroupBlock val newIndent = if (parent is SqlSubQueryGroupBlock) { diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/condition/SqlConditionKeywordGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/condition/SqlConditionKeywordGroupBlock.kt index 683b0717..34d12c27 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/condition/SqlConditionKeywordGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/condition/SqlConditionKeywordGroupBlock.kt @@ -17,6 +17,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword.condition import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlSecondOptionKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext @@ -49,7 +50,9 @@ class SqlConditionKeywordGroupBlock( override fun createBlockIndentLen(): Int { parentBlock?.let { parent -> val groupLen = parent.indent.groupIndentLen - return if (parent is SqlSubGroupBlock) { + return if (parent is SqlElConditionLoopCommentBlock) { + parent.indent.groupIndentLen + } else if (parent is SqlSubGroupBlock) { if (getNodeText() == "and") { groupLen } else { diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/second/SqlSecondKeywordBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/second/SqlSecondKeywordBlock.kt index c8506243..57e60bb7 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/second/SqlSecondKeywordBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/second/SqlSecondKeywordBlock.kt @@ -18,6 +18,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword.second import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlFunctionParamBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock @@ -44,6 +45,8 @@ open class SqlSecondKeywordBlock( offset } else if (parent is SqlSubGroupBlock) { groupLen.plus(1) + } else if (parent is SqlElConditionLoopCommentBlock) { + groupLen } else { groupLen.minus(this.getNodeText().length) } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlJoinQueriesGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlJoinQueriesGroupBlock.kt index f6e2462b..f5fd9274 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlJoinQueriesGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlJoinQueriesGroupBlock.kt @@ -17,6 +17,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword.top import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithQuerySubGroupBlock import org.domaframework.doma.intellij.formatter.util.IndentType @@ -41,10 +42,11 @@ class SqlJoinQueriesGroupBlock( override fun createBlockIndentLen(): Int { parentBlock?.let { parent -> - if (parent is SqlWithQuerySubGroupBlock) { - return parent.indent.groupIndentLen + return when (parent) { + is SqlWithQuerySubGroupBlock, is SqlElConditionLoopCommentBlock, + -> parent.indent.groupIndentLen + else -> parent.indent.groupIndentLen.plus(1) } - return parent.indent.groupIndentLen.plus(1) } return offset } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlTopQueryGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlTopQueryGroupBlock.kt index a2c33737..eb2defc9 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlTopQueryGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlTopQueryGroupBlock.kt @@ -19,6 +19,7 @@ import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.common.util.TypeUtil import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateViewGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithQuerySubGroupBlock @@ -33,6 +34,15 @@ abstract class SqlTopQueryGroupBlock( IndentType.TOP, context, ) { + companion object { + private val PARENT_INDENT_SYNC_TYPES = + listOf( + SqlCreateViewGroupBlock::class, + SqlWithQuerySubGroupBlock::class, + SqlElConditionLoopCommentBlock::class, + ) + } + override fun setParentGroupBlock(lastGroup: SqlBlock?) { super.setParentGroupBlock(lastGroup) indent.indentLevel = indentLevel @@ -46,12 +56,7 @@ abstract class SqlTopQueryGroupBlock( parentBlock?.let { parent -> if (parent.indent.indentLevel == IndentType.FILE) return 0 var baseIndent = parent.indent.groupIndentLen - val parentIndentSyncTypes = - listOf( - SqlCreateViewGroupBlock::class, - SqlWithQuerySubGroupBlock::class, - ) - if (!TypeUtil.isExpectedClassType(parentIndentSyncTypes, parent)) { + if (!TypeUtil.isExpectedClassType(PARENT_INDENT_SYNC_TYPES, parent)) { baseIndent = baseIndent.plus(1) } return baseIndent diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlDataTypeParamBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlDataTypeParamBlock.kt index 9f512389..8ebb4a00 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlDataTypeParamBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlDataTypeParamBlock.kt @@ -43,6 +43,4 @@ class SqlDataTypeParamBlock( indent.indentLen = 0 indent.groupIndentLen = 0 } - - override fun createBlockIndentLen(): Int = 0 } 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 index 669acc0d..df8d9bb9 100644 --- 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 @@ -19,6 +19,7 @@ import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.word.SqlFunctionGroupBlock import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext @@ -49,29 +50,11 @@ class SqlFunctionParamBlock( (lastGroup as? SqlFunctionGroupBlock)?.parameterGroupBlock = this } - override fun createGroupIndentLen(): Int { - val parentFunctionName = parentBlock as? SqlFunctionGroupBlock - parentFunctionName?.let { parent -> - return parent.indent.groupIndentLen - .plus(getNodeText().length) - } - - val prevChildrenDropLast = - prevChildren?.dropLast(1)?.filter { - it !is SqlLineCommentBlock && - it !is SqlBlockCommentBlock && - it.node.elementType != SqlTypes.DOT - } - ?: emptyList() - val prevLength = - prevChildrenDropLast - .sumOf { it.getNodeText().length } - .plus(getNodeText().length) - return prevLength.plus(prevChildrenDropLast.count()).plus(1) - } - override fun createBlockIndentLen(): Int { parentBlock?.let { parent -> + + if (parent is SqlElConditionLoopCommentBlock) return parent.indent.groupIndentLen + if (parent !is SqlSubGroupBlock) { return if (parent is SqlFunctionGroupBlock) { parent.indent.groupIndentLen @@ -96,4 +79,25 @@ class SqlFunctionParamBlock( } return 0 } + + override fun createGroupIndentLen(): Int { + val parentFunctionName = parentBlock as? SqlFunctionGroupBlock + parentFunctionName?.let { parent -> + return parent.indent.groupIndentLen + .plus(getNodeText().length) + } + + val prevChildrenDropLast = + prevChildren?.dropLast(1)?.filter { + it !is SqlLineCommentBlock && + it !is SqlBlockCommentBlock && + it.node.elementType != SqlTypes.DOT + } + ?: emptyList() + val prevLength = + prevChildrenDropLast + .sumOf { it.getNodeText().length } + .plus(getNodeText().length) + return prevLength.plus(prevChildrenDropLast.count()).plus(1) + } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt index 130f9399..1ec2b7fb 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt @@ -24,6 +24,7 @@ import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlRightPatternBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock import org.domaframework.doma.intellij.formatter.block.conflict.SqlDoGroupBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlLateralGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateViewGroupBlock @@ -93,7 +94,12 @@ abstract class SqlSubGroupBlock( open fun endGroup() {} - override fun createBlockIndentLen(): Int = offset + override fun createBlockIndentLen(): Int { + parentBlock?.let { parent -> + if (parent is SqlElConditionLoopCommentBlock) return parent.indent.groupIndentLen + } + return offset + } override fun createGroupIndentLen(): Int { parentBlock?.let { parent -> diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt index 17aabee0..d22981f3 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt @@ -20,6 +20,7 @@ import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlJoinGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.condition.SqlConditionalExpressionGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.top.SqlJoinQueriesGroupBlock @@ -50,23 +51,22 @@ open class SqlSubQueryGroupBlock( override fun createBlockIndentLen(): Int = parentBlock?.let { parent -> - return if (parent is SqlJoinQueriesGroupBlock) { - parent.indent.indentLen - } else if (parent is SqlWithQuerySubGroupBlock) { - parent.indent.groupIndentLen - } else if (parent is SqlJoinGroupBlock) { - parent.indent.groupIndentLen.plus(1) - } else { - val children = prevChildren?.filter { it !is SqlLineCommentBlock && it !is SqlBlockCommentBlock } - return children - ?.dropLast(1) - ?.sumOf { prev -> - prev - .getChildrenTextLen() - .plus(prev.getNodeText().length.plus(1)) - }?.plus(parent.indent.groupIndentLen) - ?.plus(1) - ?: offset + return when (parent) { + is SqlElConditionLoopCommentBlock, is SqlWithQuerySubGroupBlock -> return parent.indent.groupIndentLen + is SqlJoinQueriesGroupBlock -> return parent.indent.indentLen + is SqlJoinGroupBlock -> return parent.indent.groupIndentLen.plus(1) + else -> { + val children = prevChildren?.filter { it !is SqlLineCommentBlock && it !is SqlBlockCommentBlock } + return children + ?.dropLast(1) + ?.sumOf { prev -> + prev + .getChildrenTextLen() + .plus(prev.getNodeText().length.plus(1)) + }?.plus(parent.indent.groupIndentLen) + ?.plus(1) + ?: offset + } } } ?: offset diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/word/SqlWordBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/word/SqlWordBlock.kt index e9af5595..2ed5ccbc 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/word/SqlWordBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/word/SqlWordBlock.kt @@ -18,6 +18,7 @@ package org.domaframework.doma.intellij.formatter.block.word 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.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithCommonTableGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock import org.domaframework.doma.intellij.formatter.util.IndentType @@ -68,6 +69,10 @@ open class SqlWordBlock( return parentIndentLen.plus(1) } + is SqlElConditionLoopCommentBlock -> { + return parent.indent.groupIndentLen + } + else -> { return parent.indent.groupIndentLen.plus(1) } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt index 10379e23..bd17d4e6 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt @@ -15,14 +15,30 @@ */ package org.domaframework.doma.intellij.formatter.builder +import org.domaframework.doma.intellij.common.util.TypeUtil.isExpectedClassType import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock 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.keyword.SqlKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock import org.domaframework.doma.intellij.formatter.util.IndentType open class SqlBlockBuilder { + private val updateDirectiveParentTypes = + listOf( + SqlLineCommentBlock::class, + SqlBlockCommentBlock::class, + ) + + private val originalConditionLoopDirectiveParentType = + listOf( + SqlKeywordGroupBlock::class, + SqlSubGroupBlock::class, + ) + private val groupTopNodeIndexHistory = mutableListOf() private val commentBlocks = mutableListOf() @@ -39,31 +55,85 @@ open class SqlBlockBuilder { commentBlocks.add(block) } + /** + * For condition/loop directive blocks + * + * determine the parent based on the type of block immediately below. + */ fun updateCommentBlockIndent(baseIndent: SqlBlock) { if (commentBlocks.isNotEmpty()) { var index = 0 - commentBlocks.forEach { block -> - if (block !is SqlElBlockCommentBlock) { - if (index == 0 && - baseIndent.parentBlock is SqlSubGroupBlock && - baseIndent.parentBlock?.childBlocks?.size == 1 - ) { - block.indent.indentLevel = IndentType.NONE - block.indent.indentLen = 1 - block.indent.groupIndentLen = 0 - } else { - block.setParentGroupBlock(baseIndent) + commentBlocks + .filter { it.parentBlock == null } + .forEach { block -> + if (block !is SqlElBlockCommentBlock) { + if (index == 0 && + baseIndent.parentBlock is SqlSubGroupBlock && + baseIndent.parentBlock?.childBlocks?.size == 1 + ) { + block.indent.indentLevel = IndentType.NONE + block.indent.indentLen = 1 + block.indent.groupIndentLen = 0 + } else { + block.setParentGroupBlock(baseIndent) + } + index++ } - index++ } - } commentBlocks.clear() } - if (conditionOrLoopBlocks.isNotEmpty()) { - conditionOrLoopBlocks.forEach { block -> - if (block.parentBlock == null) { - block.setParentGroupBlock(baseIndent) - } + } + + fun updateConditionLoopBlockIndent(baseIndent: SqlBlock) { + if (!isExpectedClassType(updateDirectiveParentTypes, baseIndent)) { + if (conditionOrLoopBlocks.isNotEmpty()) { + val lastGroup = groupTopNodeIndexHistory.lastOrNull() + conditionOrLoopBlocks + .filter { it.parentBlock == null } + .forEach { block -> + var setParentBlock: SqlBlock? = null + val conditionBlockIndex = groupTopNodeIndexHistory.indexOf(block) + val prevConditionBlockGroup = + if (conditionBlockIndex > 0) { + groupTopNodeIndexHistory[conditionBlockIndex - 1] + } else { + null + } + // Prioritize previous condition loop block over keyword group + if (prevConditionBlockGroup is SqlElConditionLoopCommentBlock) { + setParentBlock = prevConditionBlockGroup + } else if (prevConditionBlockGroup?.parentBlock is SqlElConditionLoopCommentBlock) { + setParentBlock = prevConditionBlockGroup.parentBlock + } else if (lastGroup == baseIndent) { + setParentBlock = + if (isExpectedClassType( + originalConditionLoopDirectiveParentType, + baseIndent, + ) + ) { + baseIndent + } else { + prevConditionBlockGroup + } + } else { + setParentBlock = + if (isExpectedClassType( + originalConditionLoopDirectiveParentType, + baseIndent, + ) + ) { + baseIndent + } else { + prevConditionBlockGroup + } + } + + if (block != baseIndent) { + block.setParentGroupBlock(setParentBlock) + } else if (setParentBlock is SqlElConditionLoopCommentBlock) { + block.setParentGroupBlock(setParentBlock) + } + } } } } @@ -92,7 +162,7 @@ open class SqlBlockBuilder { fun getConditionOrLoopBlocksLast(): SqlElConditionLoopCommentBlock? = conditionOrLoopBlocks.lastOrNull() fun addConditionOrLoopBlock(block: SqlElConditionLoopCommentBlock) { - if (!block.conditionType.isInvalid() && !block.conditionType.isEnd()) { + if (block.conditionType.isStartDirective()) { conditionOrLoopBlocks.add(block) } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlCustomSpacingBuilder.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlCustomSpacingBuilder.kt index 160f93f4..4c49babc 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlCustomSpacingBuilder.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlCustomSpacingBuilder.kt @@ -19,15 +19,15 @@ import com.intellij.formatting.ASTBlock import com.intellij.formatting.Block import com.intellij.formatting.Spacing import com.intellij.psi.tree.IElementType +import org.domaframework.doma.intellij.common.util.TypeUtil import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlRightPatternBlock import org.domaframework.doma.intellij.formatter.block.SqlWhitespaceBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElBlockCommentBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElBlockCommentBlock.SqlElCommentDirectiveType import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnBlock import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnDefinitionRawGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateTableColumnDefinitionGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateColumnGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateValueGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlDataTypeParamBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlParallelListBlock @@ -122,6 +122,25 @@ class SqlCustomSpacingBuilder { return Spacing.createSpacing(indentLen, indentLen, 0, false, 0, 0) } + fun getSpacingElDirectiveComment( + child: SqlElBlockCommentBlock, + child2: SqlBlock, + ): Spacing? { + if (child2 is SqlRightPatternBlock) return null + if (child.directiveType == SqlElCommentDirectiveType.CONDITION_LOOP) { + val indent = child2.indent.indentLen + return Spacing.createSpacing(indent, indent, 0, false, 0, 0) + } + + if (child.directiveType == SqlElCommentDirectiveType.NORMAL || + child.directiveType == SqlElCommentDirectiveType.LITERAL + ) { + return nonSpacing + } + + return normalSpacing + } + fun getSpacingRightPattern(block: SqlRightPatternBlock): Spacing? { val parentBlock = block.parentBlock @@ -129,10 +148,7 @@ class SqlCustomSpacingBuilder { return getSpacing(block) } - if (parentBlock is SqlCreateTableColumnDefinitionGroupBlock || - parentBlock is SqlUpdateColumnGroupBlock || - parentBlock is SqlUpdateValueGroupBlock - ) { + if (TypeUtil.isExpectedClassType(SqlRightPatternBlock.NEW_LINE_EXPECTED_TYPES, parentBlock)) { return getSpacing(block) } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt index 77d622e0..1e070598 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt @@ -41,6 +41,7 @@ import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.formatter.util.SqlKeywordUtil import org.domaframework.doma.intellij.formatter.util.UpdateClauseUtil import org.domaframework.doma.intellij.psi.SqlTypes +import kotlin.collections.lastOrNull class SqlSetParentGroupProcessor( private val blockBuilder: SqlBlockBuilder, @@ -50,6 +51,16 @@ class SqlSetParentGroupProcessor( val blockBuilder: SqlBlockBuilder, ) + private val newGroupExpectedTypes = + listOf( + SqlSubGroupBlock::class, + SqlCreateViewGroupBlock::class, + SqlInlineGroupBlock::class, + SqlInlineSecondGroupBlock::class, + SqlColumnDefinitionRawGroupBlock::class, + SqlLateralGroupBlock::class, + ) + /** * Sets the parent of the latest group block and registers itself as a child element. */ @@ -60,7 +71,7 @@ class SqlSetParentGroupProcessor( blockBuilder, ), ) { history -> - return@setParentGroups history.last() + return@setParentGroups history.lastOrNull() } } @@ -106,6 +117,13 @@ class SqlSetParentGroupProcessor( blockBuilder, ) + if (lastGroupBlock is SqlElConditionLoopCommentBlock && lastGroupBlock.parentBlock != null) { + setParentGroups(context) { history -> + return@setParentGroups lastGroupBlock + } + return + } + val currentIndentLevel = childBlock.indent.indentLevel if (currentIndentLevel == IndentType.TOP) { var parentBlock: SqlBlock? = null @@ -289,12 +307,7 @@ class SqlSetParentGroupProcessor( lastGroupBlock: SqlBlock, childBlock: SqlElConditionLoopCommentBlock, ) { - val expectedTypes = - listOf( - SqlCommaBlock::class, - SqlElConditionLoopCommentBlock::class, - ) - if (isExpectedClassType(expectedTypes, lastGroupBlock)) { + if (lastGroupBlock is SqlCommaBlock) { blockBuilder.removeLastGroupTopNodeIndexHistory() } setParentGroups( @@ -303,12 +316,26 @@ class SqlSetParentGroupProcessor( blockBuilder, ), ) { history -> + if (childBlock.conditionType.isElse()) { + val lastConditionLoopCommentBlock = + blockBuilder.getConditionOrLoopBlocksLast() + return@setParentGroups lastConditionLoopCommentBlock + } if (childBlock.conditionType.isEnd()) { val lastConditionLoopCommentBlock = blockBuilder.getConditionOrLoopBlocksLast() blockBuilder.removeConditionOrLoopBlockLast() + + val directiveIndex = + blockBuilder + .getGroupTopNodeIndex { it is SqlElConditionLoopCommentBlock && it.conditionType.isStartDirective() } + if (directiveIndex >= 0) { + blockBuilder.clearSubListGroupTopNodeIndexHistory(directiveIndex) + } + return@setParentGroups lastConditionLoopCommentBlock } + return@setParentGroups null } } @@ -375,27 +402,27 @@ class SqlSetParentGroupProcessor( val parentGroup = getParentGroup(context.blockBuilder.getGroupTopNodeIndexHistory() as MutableList) + val targetChildBlock = context.childBlock + // The parent block for SqlElConditionLoopCommentBlock will be set later - if (context.childBlock !is SqlElConditionLoopCommentBlock || - context.childBlock.conditionType.isEnd() + if (targetChildBlock !is SqlElConditionLoopCommentBlock || + !targetChildBlock.conditionType.isStartDirective() ) { - context.childBlock.setParentGroupBlock(parentGroup) + targetChildBlock.setParentGroupBlock(parentGroup) } - val expectedTypes = - listOf( - SqlSubGroupBlock::class, - SqlCreateViewGroupBlock::class, - SqlInlineGroupBlock::class, - SqlInlineSecondGroupBlock::class, - SqlColumnDefinitionRawGroupBlock::class, - SqlLateralGroupBlock::class, + if (isNewGroup(targetChildBlock, context.blockBuilder) || + isExpectedClassType( + newGroupExpectedTypes, + targetChildBlock, ) - if (isNewGroup(context.childBlock, context.blockBuilder) || isExpectedClassType(expectedTypes, context.childBlock)) { - context.blockBuilder.addGroupTopNodeIndexHistory(context.childBlock) - // Set parent-child relationship and indent for preceding comment at beginning of block group - context.blockBuilder.updateCommentBlockIndent(context.childBlock) + ) { + context.blockBuilder.addGroupTopNodeIndexHistory(targetChildBlock) + context.blockBuilder.updateCommentBlockIndent(targetChildBlock) } + + // Set parent-child relationship and indent for preceding comment at beginning of block group + context.blockBuilder.updateConditionLoopBlockIndent(targetChildBlock) } /** @@ -405,6 +432,12 @@ class SqlSetParentGroupProcessor( childBlock: SqlBlock, blockBuilder: SqlBlockBuilder, ): Boolean { + if (childBlock is SqlElConditionLoopCommentBlock) { + if (childBlock.conditionType.isStartDirective()) { + return true + } + } + val lastGroup = blockBuilder.getLastGroupTopNodeIndexHistory() return isNewGroupAndNotSetLineKeywords(childBlock, lastGroup) } From 3e3fce38b6cbd29fcada2e428474581bce3ea6a6 Mon Sep 17 00:00:00 2001 From: xterao Date: Thu, 17 Jul 2025 18:49:57 +0900 Subject: [PATCH 02/11] Implement formatting support for nested structures using the else directive block. --- .../doma/intellij/formatter/block/SqlBlock.kt | 20 ++-- .../intellij/formatter/block/SqlFileBlock.kt | 3 + .../formatter/block/SqlKeywordBlock.kt | 31 ++++--- .../expr/SqlElConditionLoopCommentBlock.kt | 3 +- .../block/group/subgroup/SqlSubGroupBlock.kt | 2 +- .../formatter/builder/SqlBlockBuilder.kt | 43 ++++----- .../processor/SqlSetParentGroupProcessor.kt | 93 +++++++++++++------ .../intellij/formatter/SqlFormatterTest.kt | 4 + .../sql/formatter/NestedDirectives.sql | 37 ++++++++ .../sql/formatter/NestedDirectives_format.sql | 47 ++++++++++ .../testData/sql/formatter/WithUnionAll.sql | 6 +- .../sql/formatter/WithUnionAll_format.sql | 4 +- 12 files changed, 222 insertions(+), 71 deletions(-) create mode 100644 src/test/testData/sql/formatter/NestedDirectives.sql create mode 100644 src/test/testData/sql/formatter/NestedDirectives_format.sql 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 4615d336..4c3bb2f8 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 @@ -60,6 +60,7 @@ open class SqlBlock( open var parentBlock: SqlBlock? = null open val childBlocks = mutableListOf() + open var prevBlocks = emptyList() fun getChildrenTextLen(): Int = childBlocks.sumOf { child -> @@ -99,6 +100,7 @@ open class SqlBlock( open fun setParentGroupBlock(lastGroup: SqlBlock?) { parentBlock = lastGroup + prevBlocks = parentBlock?.childBlocks?.toList() ?: emptyList() parentBlock?.addChildBlock(this) setParentPropertyBlock(lastGroup) } @@ -108,21 +110,27 @@ open class SqlBlock( } open fun addChildBlock(childBlock: SqlBlock) { - childBlocks.add(childBlock) + if (!childBlocks.contains(childBlock)) { + childBlocks.add(childBlock) + } } fun getNodeText() = node.text.lowercase() fun isEnableFormat(): Boolean = enableFormat - open fun isSaveSpace(lastGroup: SqlBlock?): Boolean = + open fun isSaveSpace(lastGroup: SqlBlock?): Boolean { parentBlock?.let { parent -> if (parent is SqlElConditionLoopCommentBlock) { - parent.childBlocks.dropLast(1).isEmpty() - } else { - false + val prevBlock = + prevBlocks.lastOrNull { it !is SqlLineCommentBlock && it !is SqlBlockCommentBlock } + return prevBlock is SqlElConditionLoopCommentBlock && + (prevBlock.conditionType.isElse() || prevBlock.conditionType.isEnd()) || + parent.childBlocks.dropLast(1).isEmpty() } - } == true + } + return false + } /** * Creates the indentation length for the block. diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt index 377b7f80..ca476781 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt @@ -101,6 +101,9 @@ class SqlFileBlock( updateCommentParentAndIdent(childBlock) updateBlockParentAndLAddGroup(childBlock) updateWhiteSpaceInclude(lastBlock, childBlock, lastGroup) + // TODO After processing the END directive block, + // if there is only one element (with two or fewer spaces), + // remove the line breaks within the if~end block and consolidate it into a single line. blocks.add(childBlock) } else { if (lastBlock !is SqlLineCommentBlock) { diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlKeywordBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlKeywordBlock.kt index 59adf930..dba2dd24 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlKeywordBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlKeywordBlock.kt @@ -18,6 +18,7 @@ package org.domaframework.doma.intellij.formatter.block import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.block.conflict.SqlDoGroupBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock 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.keyword.with.SqlWithCommonTableGroupBlock @@ -69,9 +70,9 @@ open class SqlKeywordBlock( override fun createBlockIndentLen(): Int = when (indentLevel) { IndentType.TOP -> { - parentBlock?.let { - if (it.indent.indentLevel == IndentType.SUB) { - it.indent.groupIndentLen.plus(1) + parentBlock?.let { parent -> + if (parent.indent.indentLevel == IndentType.SUB) { + parent.indent.groupIndentLen.plus(1) } else { 0 } @@ -79,21 +80,29 @@ open class SqlKeywordBlock( } IndentType.SECOND -> { - parentBlock?.let { - it.indent.groupIndentLen - .plus(it.getNodeText().length) - .minus(this.getNodeText().length) + parentBlock?.let { parent -> + parent.indent.groupIndentLen + .plus(parent.getNodeText().length) + .minus(getNodeText().length) } ?: 1 } IndentType.INLINE_SECOND -> { - parentBlock?.let { - it.indent.groupIndentLen - .plus(it.getNodeText().length) + parentBlock?.let { parent -> + parent.indent.groupIndentLen + .plus(parent.getNodeText().length) .plus(1) } ?: 1 } - else -> 1 + else -> { + parentBlock?.let { parent -> + if (parent is SqlElConditionLoopCommentBlock) { + parent.indent.groupIndentLen + } else { + 1 + } + } ?: 1 + } } } 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 index d14edbcf..a509d39e 100644 --- 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 @@ -68,6 +68,7 @@ class SqlElConditionLoopCommentBlock( fun isElse(): Boolean = this == ELSE } + var tempParentBlock: SqlBlock? = null val conditionType: SqlConditionLoopCommentBlockType = initConditionOrLoopType(node) var conditionStart: SqlElConditionLoopCommentBlock? = null var conditionEnd: SqlElConditionLoopCommentBlock? = null @@ -114,7 +115,7 @@ class SqlElConditionLoopCommentBlock( indent.groupIndentLen = createGroupIndentLen() childBlocks.forEach { child -> - if (child is SqlElConditionLoopCommentBlock) { + if (child is SqlElConditionLoopCommentBlock && child.conditionType.isStartDirective()) { // If the child is a condition loop directive, align its indentation with the parent directive child.indent.indentLen = indent.indentLen.plus(2) } else if (child is SqlLineCommentBlock) { diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt index 1ec2b7fb..11cd2644 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt @@ -80,7 +80,7 @@ abstract class SqlSubGroupBlock( if (childBlocks.isEmpty()) { isFirstLineComment = childBlock is SqlCommentBlock } - childBlocks.add(childBlock) + super.addChildBlock(childBlock) } override fun buildChildren(): MutableList = mutableListOf() diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt index bd17d4e6..0172989a 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt @@ -55,11 +55,6 @@ open class SqlBlockBuilder { commentBlocks.add(block) } - /** - * For condition/loop directive blocks - * - * determine the parent based on the type of block immediately below. - */ fun updateCommentBlockIndent(baseIndent: SqlBlock) { if (commentBlocks.isNotEmpty()) { var index = 0 @@ -84,8 +79,15 @@ open class SqlBlockBuilder { } } - fun updateConditionLoopBlockIndent(baseIndent: SqlBlock) { - if (!isExpectedClassType(updateDirectiveParentTypes, baseIndent)) { + /** + * For condition/loop directive blocks + * determine the parent based on the type of block immediately below. + * + * When this process is invoked, a directive block has already been added to [groupTopNodeIndexHistory], + * and the parent of the block passed as [nextBlock] has already been determined. + */ + fun updateConditionLoopBlockIndent(nextBlock: SqlBlock) { + if (!isExpectedClassType(updateDirectiveParentTypes, nextBlock)) { if (conditionOrLoopBlocks.isNotEmpty()) { val lastGroup = groupTopNodeIndexHistory.lastOrNull() conditionOrLoopBlocks @@ -100,35 +102,36 @@ open class SqlBlockBuilder { null } // Prioritize previous condition loop block over keyword group - if (prevConditionBlockGroup is SqlElConditionLoopCommentBlock) { - setParentBlock = prevConditionBlockGroup - } else if (prevConditionBlockGroup?.parentBlock is SqlElConditionLoopCommentBlock) { - setParentBlock = prevConditionBlockGroup.parentBlock - } else if (lastGroup == baseIndent) { +// if (prevConditionBlockGroup is SqlElConditionLoopCommentBlock) { +// setParentBlock = prevConditionBlockGroup +// } else if (prevConditionBlockGroup?.parentBlock is SqlElConditionLoopCommentBlock) { +// setParentBlock = prevConditionBlockGroup.parentBlock +// } else + if (lastGroup == nextBlock) { setParentBlock = if (isExpectedClassType( originalConditionLoopDirectiveParentType, - baseIndent, + nextBlock, ) ) { - baseIndent + nextBlock } else { - prevConditionBlockGroup + null } } else { setParentBlock = if (isExpectedClassType( originalConditionLoopDirectiveParentType, - baseIndent, + nextBlock, ) ) { - baseIndent + nextBlock } else { prevConditionBlockGroup } } - if (block != baseIndent) { + if (block != nextBlock) { block.setParentGroupBlock(setParentBlock) } else if (setParentBlock is SqlElConditionLoopCommentBlock) { block.setParentGroupBlock(setParentBlock) @@ -159,10 +162,8 @@ open class SqlBlockBuilder { condition(it) } - fun getConditionOrLoopBlocksLast(): SqlElConditionLoopCommentBlock? = conditionOrLoopBlocks.lastOrNull() - fun addConditionOrLoopBlock(block: SqlElConditionLoopCommentBlock) { - if (block.conditionType.isStartDirective()) { + if (block.conditionType.isStartDirective() || block.conditionType.isElse()) { conditionOrLoopBlocks.add(block) } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt index 1e070598..c932d04c 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt @@ -117,9 +117,36 @@ class SqlSetParentGroupProcessor( blockBuilder, ) - if (lastGroupBlock is SqlElConditionLoopCommentBlock && lastGroupBlock.parentBlock != null) { - setParentGroups(context) { history -> - return@setParentGroups lastGroupBlock + if (lastGroupBlock is SqlElConditionLoopCommentBlock) { + if (lastGroupBlock.parentBlock != null) { + setParentGroups(context) { history -> + return@setParentGroups lastGroupBlock + } + } else { + val history = blockBuilder.getGroupTopNodeIndexHistory() + val findParent = + history + .lastOrNull { + it.indent.indentLevel < childBlock.indent.indentLevel || + (it is SqlElConditionLoopCommentBlock && it.parentBlock != null) + } + // Search for keyword groups with a level lower than or equal to the current level, + // or conditional directives that already have a parent assigned. + if (findParent is SqlElConditionLoopCommentBlock) { + // Set the parent of the most recent conditional directive to the current node. + lastGroupBlock.setParentGroupBlock(findParent) + setParentGroups(context) { history -> + return@setParentGroups lastGroupBlock + } + } + if (findParent !is SqlElConditionLoopCommentBlock) { + // If a keyword group with a level lower than or equal to the current level is found, + // set that keyword group as the parent, and set the parent of the most recent conditional directive to the current node. + setParentGroups(context) { history -> + return@setParentGroups findParent + } + lastGroupBlock.setParentGroupBlock(childBlock) + } } return } @@ -223,7 +250,9 @@ class SqlSetParentGroupProcessor( } else { setParentGroups(context) { history -> return@setParentGroups history - .lastOrNull { it.indent.indentLevel < childBlock.indent.indentLevel } + .lastOrNull { + it.indent.indentLevel < childBlock.indent.indentLevel + } } } } @@ -307,36 +336,45 @@ class SqlSetParentGroupProcessor( lastGroupBlock: SqlBlock, childBlock: SqlElConditionLoopCommentBlock, ) { - if (lastGroupBlock is SqlCommaBlock) { - blockBuilder.removeLastGroupTopNodeIndexHistory() - } - setParentGroups( + val context = SetParentContext( childBlock, blockBuilder, - ), - ) { history -> - if (childBlock.conditionType.isElse()) { - val lastConditionLoopCommentBlock = - blockBuilder.getConditionOrLoopBlocksLast() - return@setParentGroups lastConditionLoopCommentBlock - } - if (childBlock.conditionType.isEnd()) { - val lastConditionLoopCommentBlock = - blockBuilder.getConditionOrLoopBlocksLast() + ) + + if (lastGroupBlock is SqlCommaBlock) { + blockBuilder.removeLastGroupTopNodeIndexHistory() + } + setParentGroups(context) { history -> + if (childBlock.conditionType.isEnd() || childBlock.conditionType.isElse()) { + // remove self and previous conditional directive block + blockBuilder.removeConditionOrLoopBlockLast() blockBuilder.removeConditionOrLoopBlockLast() val directiveIndex = blockBuilder - .getGroupTopNodeIndex { it is SqlElConditionLoopCommentBlock && it.conditionType.isStartDirective() } + .getGroupTopNodeIndex { it is SqlElConditionLoopCommentBlock && it != childBlock } if (directiveIndex >= 0) { + val lastConditionLoopCommentBlock = + blockBuilder.getGroupTopNodeIndexHistory()[directiveIndex] blockBuilder.clearSubListGroupTopNodeIndexHistory(directiveIndex) + return@setParentGroups lastConditionLoopCommentBlock } - - return@setParentGroups lastConditionLoopCommentBlock + return@setParentGroups null } - return@setParentGroups null + // If the most recent block is a conditional directive, set it as the parent block. + if (lastGroupBlock is SqlElConditionLoopCommentBlock) { + val prevGroupIndex = blockBuilder.getGroupTopNodeIndex { it == lastGroupBlock } + if (prevGroupIndex > 0 && lastGroupBlock.parentBlock == null) { + // Determine the parent of the most recent conditional directive. + val prevGroup = blockBuilder.getGroupTopNodeIndexHistory()[prevGroupIndex - 1] + lastGroupBlock.setParentGroupBlock(prevGroup) + } + return@setParentGroups lastGroupBlock + } + // Temporary Parent Block + return@setParentGroups history.lastOrNull() } } @@ -405,9 +443,12 @@ class SqlSetParentGroupProcessor( val targetChildBlock = context.childBlock // The parent block for SqlElConditionLoopCommentBlock will be set later - if (targetChildBlock !is SqlElConditionLoopCommentBlock || - !targetChildBlock.conditionType.isStartDirective() - ) { + if (targetChildBlock is SqlElConditionLoopCommentBlock && targetChildBlock.conditionType.isStartDirective()) { + targetChildBlock.tempParentBlock = parentGroup + if (parentGroup is SqlElConditionLoopCommentBlock && parentGroup.parentBlock != null) { + targetChildBlock.setParentGroupBlock(parentGroup) + } + } else { targetChildBlock.setParentGroupBlock(parentGroup) } @@ -433,7 +474,7 @@ class SqlSetParentGroupProcessor( blockBuilder: SqlBlockBuilder, ): Boolean { if (childBlock is SqlElConditionLoopCommentBlock) { - if (childBlock.conditionType.isStartDirective()) { + if (childBlock.conditionType.isStartDirective() || childBlock.conditionType.isElse()) { return true } } 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 9044d055..ec63a3ac 100644 --- a/src/test/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatterTest.kt +++ b/src/test/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatterTest.kt @@ -166,6 +166,10 @@ class SqlFormatterTest : BasePlatformTestCase() { formatSqlFile("WithDelete.sql", "WithDelete$formatDataPrefix.sql") } + fun testNestedDirectivesFormatter() { + formatSqlFile("NestedDirectives.sql", "NestedDirectives$formatDataPrefix.sql") + } + private fun formatSqlFile( beforeFile: String, afterFile: String, diff --git a/src/test/testData/sql/formatter/NestedDirectives.sql b/src/test/testData/sql/formatter/NestedDirectives.sql new file mode 100644 index 00000000..888da92f --- /dev/null +++ b/src/test/testData/sql/formatter/NestedDirectives.sql @@ -0,0 +1,37 @@ +SELECT e.id , e.name , d.name AS department_name + FROM employee e + /*%if includesDepartment */ + LEFT JOIN department d ON e.department_id = d.id + /*%if includeDepartmentDetails */ + LEFT +JOIN department_detail dd ON d.id = dd.department_id + /*%end */ /*%end */ + WHERE 1 = 1 ORDER BY + /*%if sortConditions != null && !sortConditions.isEmpty() */ -- IF1 + /*%for sort : sortConditions */ -- IF2 + /*%if sort.field == "name" */ -- IF3 +e.name + /*%if sort.direction == "DESC" */ -- IF4 + DESC /*%else */ -- ELSE4 + ASC + /*%end */ -- END4 + /*%elseif sort.field == "department" */ -- ELSE3 + /*%if includesDepartment */ -- IF5 + d.name /*%if sort.direction == "DESC" */ -- IF6 + DESC /*%else */ -- ELSE6 + ASC /*%end */ -- END6 + /*%else */ -- ELSE5 + e.department_id /*%if sort.direction == "DESC" */ -- IF7 + DESC + /*%else */ -- ELSE7 +ASC + /*%end */ -- END7 + /*%end */ -- END5 + /*%end */ -- END3 + /*%if sort_has_next */ -- IF8 +, +/*%end */ -- END8 + /*%end */ -- END2 + /*%else */ -- ELSE1 + e.id ASC + /*%end */ -- END1 \ No newline at end of file diff --git a/src/test/testData/sql/formatter/NestedDirectives_format.sql b/src/test/testData/sql/formatter/NestedDirectives_format.sql new file mode 100644 index 00000000..075d86ae --- /dev/null +++ b/src/test/testData/sql/formatter/NestedDirectives_format.sql @@ -0,0 +1,47 @@ +SELECT e.id + , e.name + , d.name AS department_name + FROM employee e + /*%if includesDepartment */ + LEFT JOIN department d + ON e.department_id = d.id + /*%if includeDepartmentDetails */ + LEFT JOIN department_detail dd + ON d.id = dd.department_id + /*%end */ + /*%end */ + WHERE 1 = 1 + ORDER BY + /*%if sortConditions != null && !sortConditions.isEmpty() */ -- IF1 + /*%for sort : sortConditions */ -- IF2 + /*%if sort.field == "name" */ -- IF3 + e.name + /*%if sort.direction == "DESC" */ -- IF4 + DESC + /*%else */ -- ELSE4 + ASC + /*%end */ -- END4 + /*%elseif sort.field == "department" */ -- ELSE3 + /*%if includesDepartment */ -- IF5 + d.name + /*%if sort.direction == "DESC" */ -- IF6 + DESC + /*%else */ -- ELSE6 + ASC + /*%end */ -- END6 + /*%else */ -- ELSE5 + e.department_id + /*%if sort.direction == "DESC" */ -- IF7 + DESC + /*%else */ -- ELSE7 + ASC + /*%end */ -- END7 + /*%end */ -- END5 + /*%end */ -- END3 + /*%if sort_has_next */ -- IF8 + , + /*%end */ -- END8 + /*%end */ -- END2 + /*%else */ -- ELSE1 + e.id ASC + /*%end */ -- END1 diff --git a/src/test/testData/sql/formatter/WithUnionAll.sql b/src/test/testData/sql/formatter/WithUnionAll.sql index a2bfb3fb..f513684a 100644 --- a/src/test/testData/sql/formatter/WithUnionAll.sql +++ b/src/test/testData/sql/formatter/WithUnionAll.sql @@ -1,12 +1,12 @@ with tables AS ( ( SELECT top, no_pre_as AS AS_NAME, pre_as, clm3 from demo -WHERE id = /*# "block" */1 ) +WHERE id = /*# "block" */ ) UNION ALL ( SELECT id2, no_pre_as2 AS AS_NAME2, pre_as2 FROM demo2 - WHERE id2 = /*# "block2" */1 ) ) + WHERE id2 = /*# "block2" */ ) ) SELECT query.id3 , query.no_pre_as3 AS AS_NAME3 , query.pre_as3 FROM demo3 query INNER JOIN query1 q1 ON q1.id = query.id3 LEFT JOIN query1 q2 ON query.id3 = q2.id AND query.pre_as3 = q2.sub_id - WHERE query.id3 = /* id */1 + WHERE query.id3 = /* id */ 1 ORDER BY query.id3, query.pre_as3 diff --git a/src/test/testData/sql/formatter/WithUnionAll_format.sql b/src/test/testData/sql/formatter/WithUnionAll_format.sql index dd3cfc4b..05808026 100644 --- a/src/test/testData/sql/formatter/WithUnionAll_format.sql +++ b/src/test/testData/sql/formatter/WithUnionAll_format.sql @@ -4,13 +4,13 @@ WITH tables AS ( , pre_as , clm3 FROM demo - WHERE id = /*# "block" */1 ) + WHERE id = /*# "block" */ ) UNION ALL ( SELECT id2 , no_pre_as2 AS AS_NAME2 , pre_as2 FROM demo2 - WHERE id2 = /*# "block2" */1 ) + WHERE id2 = /*# "block2" */ ) ) SELECT query.id3 , query.no_pre_as3 AS AS_NAME3 From bd4ea517a6ecf705d007c4ae6f5469045ba1098d Mon Sep 17 00:00:00 2001 From: xterao Date: Fri, 18 Jul 2025 13:07:08 +0900 Subject: [PATCH 03/11] Refactor SQL formatting classes to improve spacing and indentation handling for various SQL constructs --- .../doma/intellij/formatter/block/SqlBlock.kt | 2 +- .../intellij/formatter/block/SqlCommaBlock.kt | 1 + .../intellij/formatter/block/SqlFileBlock.kt | 45 +++++++-- .../formatter/block/SqlRightPatternBlock.kt | 92 ++++++++++++++----- .../block/conflict/OnConflictKeywordType.kt | 15 ++- .../group/keyword/SqlKeywordGroupBlock.kt | 16 +++- .../block/group/subgroup/SqlSubGroupBlock.kt | 19 ++-- .../builder/SqlCustomSpacingBuilder.kt | 27 +----- .../processor/SqlSetParentGroupProcessor.kt | 4 - .../intellij/formatter/util/SqlBlockUtil.kt | 7 +- 10 files changed, 147 insertions(+), 81 deletions(-) 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 4c3bb2f8..8af3645b 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 @@ -82,7 +82,7 @@ open class SqlBlock( fun getChildBlocksDropLast( dropIndex: Int = 1, - skipCommentBlock: Boolean = false, + skipCommentBlock: Boolean = true, ): List { val children = childBlocks.dropLast(dropIndex) if (skipCommentBlock) { 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 1931e5ca..fce3afdc 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 @@ -58,6 +58,7 @@ open class SqlCommaBlock( SqlFunctionParamBlock::class, SqlWithColumnGroupBlock::class, SqlKeywordGroupBlock::class, + SqlElConditionLoopCommentBlock::class, ) private val PARENT_INDENT_SYNC_TYPES = diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt index ca476781..70e6ee74 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt @@ -78,6 +78,17 @@ class SqlFileBlock( enableFormat, formatMode, ) { + override val indent = + ElementIndent( + IndentType.FILE, + 0, + 0, + ) + + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(null) + } + private val blocks = mutableListOf() private val blockBuilder = SqlBlockBuilder() @@ -446,11 +457,21 @@ class SqlFileBlock( if (childBlock1 is SqlWhitespaceBlock && childBlock2.parentBlock is SqlElConditionLoopCommentBlock) { val child1 = childBlock2.parentBlock as SqlElConditionLoopCommentBlock - SqlCustomSpacingBuilder().getSpacingElDirectiveComment(child1, childBlock2)?.let { return it } + SqlCustomSpacingBuilder() + .getSpacingElDirectiveComment(child1, childBlock2) + ?.let { return it } } - if (childBlock1 is SqlElBlockCommentBlock) { - SqlCustomSpacingBuilder().getSpacingElDirectiveComment(childBlock1, childBlock2)?.let { return it } + if (childBlock1 is SqlElBlockCommentBlock && childBlock2 !is SqlRightPatternBlock) { + SqlCustomSpacingBuilder() + .getSpacingElDirectiveComment(childBlock1, childBlock2) + ?.let { return it } + } + + if (childBlock2 is SqlRightPatternBlock) { + return SqlCustomSpacingBuilder().getSpacingRightPattern( + childBlock2, + ) } if (childBlock2 is SqlWithColumnGroupBlock) { @@ -467,7 +488,11 @@ class SqlFileBlock( } if (childBlock2 is SqlElBlockCommentBlock) { - if (TypeUtil.isExpectedClassType(SqlRightPatternBlock.NOT_INSERT_SPACE_TYPES, childBlock1)) { + if (TypeUtil.isExpectedClassType( + SqlRightPatternBlock.NOT_INDENT_EXPECTED_TYPES, + childBlock1, + ) + ) { return SqlCustomSpacingBuilder.nonSpacing } return when (childBlock1) { @@ -530,7 +555,9 @@ class SqlFileBlock( } // Create Table Column Definition Raw Group Block - CreateTableUtil.getColumnDefinitionRawGroupSpacing(childBlock1, childBlock2)?.let { return it } + CreateTableUtil + .getColumnDefinitionRawGroupSpacing(childBlock1, childBlock2) + ?.let { return it } when (childBlock2) { is SqlColumnDefinitionRawGroupBlock -> @@ -539,10 +566,6 @@ class SqlFileBlock( childBlock2, )?.let { return it } - is SqlRightPatternBlock -> return SqlCustomSpacingBuilder().getSpacingRightPattern( - childBlock2, - ) - is SqlColumnBlock -> SqlCustomSpacingBuilder() .getSpacingColumnDefinition(childBlock2) @@ -550,7 +573,9 @@ class SqlFileBlock( } if (childBlock1 is SqlBlock && (childBlock2 is SqlCommaBlock || childBlock2 is SqlColumnRawGroupBlock)) { - SqlCustomSpacingBuilder().getSpacingWithIndentComma(childBlock1, childBlock2)?.let { return it } + SqlCustomSpacingBuilder() + .getSpacingWithIndentComma(childBlock1, childBlock2) + ?.let { return it } } val spacing: Spacing? = customSpacingBuilder?.getCustomSpacing(childBlock1, childBlock2) 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 02126929..deddd73b 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 @@ -24,6 +24,7 @@ import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordG import org.domaframework.doma.intellij.formatter.block.group.keyword.condition.SqlConditionalExpressionGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateTableColumnDefinitionGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlValuesGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateColumnGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateSetGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateValueGroupBlock @@ -49,10 +50,25 @@ open class SqlRightPatternBlock( context.enableFormat, context.formatMode, ) { - var preSpaceRight = false + enum class LineBreakAndSpacingType { + NONE, // No line break and no spacing + LINE_BREAK, // Line break only + SPACING, // Spacing only + LINE_BREAK_AND_SPACING, // Both line break and spacing + } + + private var preSpaceRight = false + var lineBreakAndSpacingType: LineBreakAndSpacingType = LineBreakAndSpacingType.NONE companion object { - val NOT_INSERT_SPACE_TYPES = + private val INDENT_EXPECTED_TYPES = + listOf( + SqlUpdateColumnGroupBlock::class, + SqlUpdateValueGroupBlock::class, + SqlCreateTableColumnDefinitionGroupBlock::class, + ) + + val NOT_INDENT_EXPECTED_TYPES = listOf( SqlFunctionParamBlock::class, SqlInsertColumnGroupBlock::class, @@ -61,13 +77,6 @@ open class SqlRightPatternBlock( SqlConditionalExpressionGroupBlock::class, ) - private val INDENT_EXPECTED_TYPES = - listOf( - SqlUpdateColumnGroupBlock::class, - SqlUpdateValueGroupBlock::class, - SqlCreateTableColumnDefinitionGroupBlock::class, - ) - val NEW_LINE_EXPECTED_TYPES = listOf( SqlUpdateColumnGroupBlock::class, @@ -78,7 +87,7 @@ open class SqlRightPatternBlock( SqlWithQuerySubGroupBlock::class, ) - private val NEW_LINE_EXCLUDE_TYPES = + val NOT_NEW_LINE_EXPECTED_TYPES = listOf( SqlDataTypeParamBlock::class, SqlConditionalExpressionGroupBlock::class, @@ -93,11 +102,16 @@ open class SqlRightPatternBlock( private fun enableLastRight() { parentBlock?.let { parent -> // Check if parent is in the notInsertSpaceClassList - if (isExpectedClassType(NOT_INSERT_SPACE_TYPES, parent)) { + if (isExpectedClassType(NOT_INDENT_EXPECTED_TYPES, parent)) { preSpaceRight = false return } - if (isExpectedClassType(INDENT_EXPECTED_TYPES, parent)) { + if (isExpectedClassType( + INDENT_EXPECTED_TYPES, + parent, + ) || + parent.childBlocks.firstOrNull() is SqlValuesGroupBlock + ) { preSpaceRight = true return } @@ -146,9 +160,16 @@ open class SqlRightPatternBlock( override fun buildChildren(): MutableList = mutableListOf() override fun createBlockIndentLen(): Int { - if (preSpaceRight) return 1 - parentBlock?.let { parent -> + if (( + isExpectedClassType(NEW_LINE_EXPECTED_TYPES, parent) || + parent.getChildBlocksDropLast().firstOrNull() is SqlValuesGroupBlock + ) && + preSpaceRight + ) { + return parent.indent.indentLen + } + if (preSpaceRight) return 1 return parent.indent.indentLen } ?: return 0 } @@ -156,26 +177,51 @@ open class SqlRightPatternBlock( override fun isLeaf(): Boolean = true override fun isSaveSpace(lastGroup: SqlBlock?): Boolean { - if (preSpaceRight) return false - parentBlock?.let { parent -> - if (( - isExpectedClassType(NEW_LINE_EXPECTED_TYPES, parent) || - isExpectedClassType(NEW_LINE_EXPECTED_TYPES, parent.parentBlock) - ) && - !isExpectedClassType(NEW_LINE_EXCLUDE_TYPES, parent) + if (isExpectedClassType(NEW_LINE_EXPECTED_TYPES, parent) || + parent.childBlocks.firstOrNull() is SqlValuesGroupBlock ) { + lineBreakAndSpacingType = + if (preSpaceRight) { + LineBreakAndSpacingType.LINE_BREAK_AND_SPACING + } else { + LineBreakAndSpacingType.LINE_BREAK + } return true } if (parent is SqlSubGroupBlock) { val firstChild = - parent.getChildBlocksDropLast(skipCommentBlock = true).firstOrNull() + parent.getChildBlocksDropLast().firstOrNull() if (firstChild is SqlKeywordGroupBlock) { - return firstChild.indent.indentLevel != IndentType.TOP + val lineBreak = + firstChild.indent.indentLevel != IndentType.TOP && + !isExpectedClassType(NOT_NEW_LINE_EXPECTED_TYPES, parent) + lineBreakAndSpacingType = + if (lineBreak) { + if (preSpaceRight) { + LineBreakAndSpacingType.LINE_BREAK_AND_SPACING + } else { + LineBreakAndSpacingType.LINE_BREAK + } + } else { + if (preSpaceRight) { + LineBreakAndSpacingType.SPACING + } else { + LineBreakAndSpacingType.NONE + } + } + + return lineBreak } } } + lineBreakAndSpacingType = + if (preSpaceRight) { + LineBreakAndSpacingType.SPACING + } else { + LineBreakAndSpacingType.NONE + } return false } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/conflict/OnConflictKeywordType.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/conflict/OnConflictKeywordType.kt index 651925c0..43c1f823 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/conflict/OnConflictKeywordType.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/conflict/OnConflictKeywordType.kt @@ -15,8 +15,15 @@ */ package org.domaframework.doma.intellij.formatter.block.conflict -enum class OnConflictKeywordType { - CONFLICT, - CONSTRAINT, - UNKNOWN, +enum class OnConflictKeywordType( + private val keyword: String, +) { + CONFLICT("conflict"), + CONSTRAINT("constraint"), + UNKNOWN("unknown"), + ; + + companion object { + fun of(keyword: String): OnConflictKeywordType = entries.find { it.keyword == keyword } ?: UNKNOWN + } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt index bb759e5c..84030cbd 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt @@ -39,14 +39,20 @@ open class SqlKeywordGroupBlock( fun updateTopKeywordBlocks(block: SqlBlock) { val lastChild = - getChildBlocksDropLast(skipCommentBlock = true).lastOrNull() + getChildBlocksDropLast().lastOrNull() val topKeywordTypes = listOf( SqlKeywordBlock::class, SqlKeywordGroupBlock::class, ) - if (lastChild == null || TypeUtil.isExpectedClassType(topKeywordTypes, lastChild) && canAddTopKeyword) { + if (lastChild == null || + TypeUtil.isExpectedClassType( + topKeywordTypes, + lastChild, + ) && + canAddTopKeyword + ) { topKeywordBlocks.add(block) } else { canAddTopKeyword = false @@ -168,5 +174,9 @@ open class SqlKeywordGroupBlock( override fun createGroupIndentLen(): Int = indent.indentLen.plus(topKeywordBlocks.sumOf { it.getNodeText().length.plus(1) }.minus(1)) - override fun isSaveSpace(lastGroup: SqlBlock?): Boolean = true + override fun isSaveSpace(lastGroup: SqlBlock?): Boolean { + val prevWord = prevBlocks.lastOrNull() + return !SqlKeywordUtil.isSetLineKeyword(this.getNodeText(), prevWord?.getNodeText() ?: "") && + !SqlKeywordUtil.isSetLineKeyword(this.getNodeText(), lastGroup?.getNodeText() ?: "") + } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt index 11cd2644..d02d95c8 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt @@ -43,6 +43,16 @@ abstract class SqlSubGroupBlock( node, context, ) { + companion object { + private val NEW_LINE_EXPECTED_TYPES = + listOf( + SqlWithQueryGroupBlock::class, + SqlWithCommonTableGroupBlock::class, + SqlWithColumnGroupBlock::class, + SqlCreateViewGroupBlock::class, + ) + } + open val offset = 1 // TODO Even if the first element of a subgroup is a comment, @@ -112,14 +122,7 @@ abstract class SqlSubGroupBlock( override fun isSaveSpace(lastGroup: SqlBlock?): Boolean { lastGroup?.let { lastBlock -> if (lastBlock is SqlJoinQueriesGroupBlock) return true - val expectedTypes = - listOf( - SqlWithQueryGroupBlock::class, - SqlWithCommonTableGroupBlock::class, - SqlWithColumnGroupBlock::class, - SqlCreateViewGroupBlock::class, - ) - return TypeUtil.isExpectedClassType(expectedTypes, lastBlock.parentBlock) + return TypeUtil.isExpectedClassType(NEW_LINE_EXPECTED_TYPES, lastBlock.parentBlock) } return false } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlCustomSpacingBuilder.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlCustomSpacingBuilder.kt index 4c49babc..e0170c28 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlCustomSpacingBuilder.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlCustomSpacingBuilder.kt @@ -141,27 +141,10 @@ class SqlCustomSpacingBuilder { return normalSpacing } - fun getSpacingRightPattern(block: SqlRightPatternBlock): Spacing? { - val parentBlock = block.parentBlock - - if (block.isSaveSpace(null)) { - return getSpacing(block) - } - - if (TypeUtil.isExpectedClassType(SqlRightPatternBlock.NEW_LINE_EXPECTED_TYPES, parentBlock)) { - return getSpacing(block) + fun getSpacingRightPattern(block: SqlRightPatternBlock): Spacing? = + when (block.lineBreakAndSpacingType) { + SqlRightPatternBlock.LineBreakAndSpacingType.NONE, SqlRightPatternBlock.LineBreakAndSpacingType.LINE_BREAK -> nonSpacing + SqlRightPatternBlock.LineBreakAndSpacingType.SPACING -> normalSpacing + SqlRightPatternBlock.LineBreakAndSpacingType.LINE_BREAK_AND_SPACING -> getSpacing(block) } - - if (parentBlock is SqlParallelListBlock) { - val lastKeywordGroup = parentBlock.getChildBlocksDropLast().lastOrNull() - return if (lastKeywordGroup is SqlKeywordGroupBlock) { - normalSpacing - } else { - nonSpacing - } - } - - if (parentBlock is SqlDataTypeParamBlock || !block.preSpaceRight) return nonSpacing - return normalSpacing - } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt index c932d04c..27a1e43e 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt @@ -341,10 +341,6 @@ class SqlSetParentGroupProcessor( childBlock, blockBuilder, ) - - if (lastGroupBlock is SqlCommaBlock) { - blockBuilder.removeLastGroupTopNodeIndexHistory() - } setParentGroups(context) { history -> if (childBlock.conditionType.isEnd() || childBlock.conditionType.isElse()) { // remove self and previous conditional directive block diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockUtil.kt index 6835cae8..25abe210 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockUtil.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockUtil.kt @@ -137,12 +137,7 @@ class SqlBlockUtil( IndentType.CONFLICT -> { if (lastGroupBlock is SqlConflictClauseBlock) { - lastGroupBlock.conflictType = - when (keywordText) { - "conflict" -> OnConflictKeywordType.CONFLICT - "constraint" -> OnConflictKeywordType.CONSTRAINT - else -> OnConflictKeywordType.UNKNOWN - } + lastGroupBlock.conflictType = OnConflictKeywordType.of(keywordText) return SqlKeywordBlock(child, indentLevel, sqlBlockFormattingCtx) } else { return SqlConflictClauseBlock(child, sqlBlockFormattingCtx) From 24f87abde3236d7f86e83f1ff7a30e6d92dc98b8 Mon Sep 17 00:00:00 2001 From: xterao Date: Fri, 18 Jul 2025 13:07:54 +0900 Subject: [PATCH 04/11] Refactor SQL comment block classes to improve structure and indentation handling --- .../doma/intellij/formatter/block/SqlBlock.kt | 5 +- .../intellij/formatter/block/SqlCommaBlock.kt | 1 + .../intellij/formatter/block/SqlFileBlock.kt | 13 ++++-- .../formatter/block/SqlKeywordBlock.kt | 2 +- .../block/comment/SqlBlockCommentBlock.kt | 2 +- .../block/comment/SqlCommentBlock.kt | 4 +- .../block/comment/SqlDefaultCommentBlock.kt | 46 +++++++++++++++++++ .../SqlElBlockCommentBlock.kt | 22 ++------- .../SqlElConditionLoopCommentBlock.kt | 20 ++------ .../block/comment/SqlLineCommentBlock.kt | 41 +---------------- .../block/group/keyword/SqlJoinGroupBlock.kt | 2 +- .../group/keyword/SqlKeywordGroupBlock.kt | 2 +- .../group/keyword/SqlLateralGroupBlock.kt | 2 +- .../SqlSecondOptionKeywordGroupBlock.kt | 2 +- .../SqlConditionKeywordGroupBlock.kt | 2 +- .../keyword/second/SqlSecondKeywordBlock.kt | 2 +- .../keyword/top/SqlJoinQueriesGroupBlock.kt | 2 +- .../keyword/top/SqlSelectQueryGroupBlock.kt | 2 +- .../keyword/top/SqlTopQueryGroupBlock.kt | 2 +- .../group/subgroup/SqlFunctionParamBlock.kt | 2 +- .../block/group/subgroup/SqlSubGroupBlock.kt | 2 +- .../group/subgroup/SqlSubQueryGroupBlock.kt | 2 +- .../formatter/block/word/SqlWordBlock.kt | 2 +- .../formatter/builder/SqlBlockBuilder.kt | 39 +++++----------- .../builder/SqlCustomSpacingBuilder.kt | 7 +-- .../processor/SqlSetParentGroupProcessor.kt | 3 +- .../intellij/formatter/util/SqlBlockUtil.kt | 4 +- 27 files changed, 105 insertions(+), 130 deletions(-) create mode 100644 src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlDefaultCommentBlock.kt rename src/main/kotlin/org/domaframework/doma/intellij/formatter/block/{expr => comment}/SqlElBlockCommentBlock.kt (91%) rename src/main/kotlin/org/domaframework/doma/intellij/formatter/block/{expr => comment}/SqlElConditionLoopCommentBlock.kt (94%) 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 8af3645b..3484447c 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 @@ -25,8 +25,9 @@ import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlDefaultCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.psi.SqlTypes @@ -123,7 +124,7 @@ open class SqlBlock( parentBlock?.let { parent -> if (parent is SqlElConditionLoopCommentBlock) { val prevBlock = - prevBlocks.lastOrNull { it !is SqlLineCommentBlock && it !is SqlBlockCommentBlock } + prevBlocks.lastOrNull { it !is SqlDefaultCommentBlock } return prevBlock is SqlElConditionLoopCommentBlock && (prevBlock.conditionType.isElse() || prevBlock.conditionType.isEnd()) || parent.childBlocks.dropLast(1).isEmpty() 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 fce3afdc..4444745f 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 @@ -18,6 +18,7 @@ package org.domaframework.doma.intellij.formatter.block import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.common.util.TypeUtil +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnRawGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.condition.SqlConditionalExpressionGroupBlock diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt index 70e6ee74..941123cb 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt @@ -29,9 +29,10 @@ import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.common.util.TypeUtil import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlDefaultCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElBlockCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock -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.expr.SqlElSymbolBlock import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnBlock @@ -266,7 +267,11 @@ class SqlFileBlock( commentBlock, ) } else { - blockBuilder.addCommentBlock(commentBlock) + (commentBlock as? SqlDefaultCommentBlock)?.let { + blockBuilder.addCommentBlock( + commentBlock, + ) + } } } @@ -360,7 +365,7 @@ class SqlFileBlock( ) } - is SqlWordBlock, is SqlOtherBlock, is SqlLineCommentBlock, is SqlBlockCommentBlock -> { + is SqlWordBlock, is SqlOtherBlock, is SqlDefaultCommentBlock -> { parentSetProcessor.updateGroupBlockParentAndAddGroup( childBlock, ) diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlKeywordBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlKeywordBlock.kt index dba2dd24..4bb701da 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlKeywordBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlKeywordBlock.kt @@ -17,8 +17,8 @@ package org.domaframework.doma.intellij.formatter.block import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.conflict.SqlDoGroupBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock 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.keyword.with.SqlWithCommonTableGroupBlock diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlBlockCommentBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlBlockCommentBlock.kt index 04b11ab0..ead89a35 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlBlockCommentBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlBlockCommentBlock.kt @@ -23,7 +23,7 @@ import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext open class SqlBlockCommentBlock( node: ASTNode, context: SqlBlockFormattingContext, -) : SqlCommentBlock( +) : SqlDefaultCommentBlock( node, context, ) { diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlCommentBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlCommentBlock.kt index f3833c4a..bc19c1f9 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlCommentBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlCommentBlock.kt @@ -44,7 +44,7 @@ abstract class SqlCommentBlock( super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.NONE indent.indentLen = createBlockIndentLen() - indent.groupIndentLen = 0 + indent.groupIndentLen = createGroupIndentLen() } override fun buildChildren(): MutableList = mutableListOf() @@ -61,4 +61,6 @@ abstract class SqlCommentBlock( } return 0 } + + override fun createGroupIndentLen(): Int = 0 } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlDefaultCommentBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlDefaultCommentBlock.kt new file mode 100644 index 00000000..96ef29f9 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlDefaultCommentBlock.kt @@ -0,0 +1,46 @@ +/* + * 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.comment + +import com.intellij.lang.ASTNode +import com.intellij.psi.formatter.common.AbstractBlock +import com.intellij.psi.util.PsiTreeUtil +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.SqlFileBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext + +abstract class SqlDefaultCommentBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlCommentBlock(node, context) { + override fun buildChildren(): MutableList = mutableListOf() + + override fun isLeaf(): Boolean = true + + /** + * When the next element block is determined, update the indent to align it with the element below. + */ + fun updateIndentLen(baseBlock: SqlBlock) { + indent.indentLen = + if (parentBlock is SqlFileBlock || isSaveSpace(parentBlock)) { + baseBlock.indent.indentLen + } else { + 1 + } + } + + override fun isSaveSpace(lastGroup: SqlBlock?) = PsiTreeUtil.prevLeaf(node.psi)?.text?.contains("\n") == true +} 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/comment/SqlElBlockCommentBlock.kt similarity index 91% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElBlockCommentBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElBlockCommentBlock.kt index ec180bdd..43ecc6e4 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElBlockCommentBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElBlockCommentBlock.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.expr +package org.domaframework.doma.intellij.formatter.block.comment import com.intellij.formatting.Block import com.intellij.formatting.Spacing @@ -25,12 +25,12 @@ import com.intellij.psi.util.elementType import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlOperationBlock import org.domaframework.doma.intellij.formatter.block.SqlUnknownBlock -import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock -import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElFieldAccessBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElFunctionCallBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElStaticFieldAccessBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlValuesGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder -import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext import org.domaframework.doma.intellij.psi.SqlElElseifDirective import org.domaframework.doma.intellij.psi.SqlElForDirective @@ -53,20 +53,6 @@ open class SqlElBlockCommentBlock( val directiveType: SqlElCommentDirectiveType = initDirectiveType() - override val indent = - ElementIndent( - IndentType.NONE, - 0, - 0, - ) - - override fun setParentGroupBlock(lastGroup: SqlBlock?) { - super.setParentGroupBlock(lastGroup) - indent.indentLevel = IndentType.NONE - indent.indentLen = createBlockIndentLen() - indent.groupIndentLen = 0 - } - private fun initDirectiveType(): SqlElCommentDirectiveType { val element = this.node.psi val contentElement = PsiTreeUtil.firstChild(element).nextSibling 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/comment/SqlElConditionLoopCommentBlock.kt similarity index 94% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElConditionLoopCommentBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt index a509d39e..45fb3258 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElConditionLoopCommentBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.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.expr +package org.domaframework.doma.intellij.formatter.block.comment import com.intellij.formatting.Block import com.intellij.formatting.Spacing @@ -29,15 +29,15 @@ import org.domaframework.doma.intellij.formatter.block.SqlCommaBlock import org.domaframework.doma.intellij.formatter.block.SqlOperationBlock import org.domaframework.doma.intellij.formatter.block.SqlRightPatternBlock import org.domaframework.doma.intellij.formatter.block.SqlUnknownBlock -import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock -import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElFieldAccessBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElFunctionCallBlock +import org.domaframework.doma.intellij.formatter.block.expr.SqlElStaticFieldAccessBlock import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnRawGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertQueryGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder -import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext import org.domaframework.doma.intellij.psi.SqlCustomElCommentExpr import org.domaframework.doma.intellij.psi.SqlElForDirective @@ -95,13 +95,6 @@ class SqlElConditionLoopCommentBlock( return SqlConditionLoopCommentBlockType.UNKNOWN } - override val indent = - ElementIndent( - IndentType.NONE, - 0, - 0, - ) - /** * Initially, set a **provisional indentation level** for conditional directives. * @@ -110,9 +103,6 @@ class SqlElConditionLoopCommentBlock( */ override fun setParentGroupBlock(lastGroup: SqlBlock?) { super.setParentGroupBlock(lastGroup) - indent.indentLevel = IndentType.NONE - indent.indentLen = createBlockIndentLen() - indent.groupIndentLen = createGroupIndentLen() childBlocks.forEach { child -> if (child is SqlElConditionLoopCommentBlock && child.conditionType.isStartDirective()) { @@ -253,7 +243,7 @@ class SqlElConditionLoopCommentBlock( } } return if (TypeUtil.isExpectedClassType( - SqlRightPatternBlock.NOT_INSERT_SPACE_TYPES, + SqlRightPatternBlock.NOT_INDENT_EXPECTED_TYPES, parent, ) ) { diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlLineCommentBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlLineCommentBlock.kt index d0f0d0d6..8e34f9b1 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlLineCommentBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlLineCommentBlock.kt @@ -16,49 +16,12 @@ package org.domaframework.doma.intellij.formatter.block.comment import com.intellij.lang.ASTNode -import com.intellij.psi.formatter.common.AbstractBlock -import com.intellij.psi.util.PsiTreeUtil -import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext open class SqlLineCommentBlock( node: ASTNode, context: SqlBlockFormattingContext, -) : SqlCommentBlock( +) : SqlDefaultCommentBlock( node, context, - ) { - override fun setParentGroupBlock(lastGroup: SqlBlock?) { - super.setParentGroupBlock(lastGroup) - indent.indentLen = createBlockIndentLen() - } - - override fun buildChildren(): MutableList = mutableListOf() - - override fun isLeaf(): Boolean = true - - override fun createBlockIndentLen(): Int { - val prevElement = PsiTreeUtil.prevLeaf(node.psi, false) - if (prevElement?.text?.contains("\n") != true && - prevElement != null && - PsiTreeUtil.prevLeaf(prevElement) !is SqlLineCommentBlock - ) { - return 1 - } - parentBlock?.let { parent -> - if (parent is SqlSubQueryGroupBlock) { - if (parent.getChildBlocksDropLast().isEmpty()) { - return 0 - } - if (parent.isFirstLineComment) { - return parent.indent.groupIndentLen.minus(2) - } - } - return parent.indent.indentLen - } - return 0 - } - - override fun isSaveSpace(lastGroup: SqlBlock?) = PsiTreeUtil.prevLeaf(node.psi)?.text?.contains("\n") == true -} + ) diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlJoinGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlJoinGroupBlock.kt index 51f38dd2..7541feb0 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlJoinGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlJoinGroupBlock.kt @@ -18,7 +18,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword 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.expr.SqlElConditionLoopCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt index 84030cbd..dba66ccd 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt @@ -20,7 +20,7 @@ import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.common.util.TypeUtil import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.top.SqlSelectQueryGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithCommonTableGroupBlock diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlLateralGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlLateralGroupBlock.kt index 29da9958..f7bdfc7d 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlLateralGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlLateralGroupBlock.kt @@ -17,7 +17,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlFromGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock import org.domaframework.doma.intellij.formatter.util.IndentType diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlSecondOptionKeywordGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlSecondOptionKeywordGroupBlock.kt index 1c8136a7..2ec0be52 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlSecondOptionKeywordGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlSecondOptionKeywordGroupBlock.kt @@ -18,7 +18,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock 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.util.IndentType diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/condition/SqlConditionKeywordGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/condition/SqlConditionKeywordGroupBlock.kt index 34d12c27..41a69b4b 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/condition/SqlConditionKeywordGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/condition/SqlConditionKeywordGroupBlock.kt @@ -17,7 +17,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword.condition import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlSecondOptionKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/second/SqlSecondKeywordBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/second/SqlSecondKeywordBlock.kt index 57e60bb7..018f1308 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/second/SqlSecondKeywordBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/second/SqlSecondKeywordBlock.kt @@ -18,7 +18,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword.second import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlFunctionParamBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlJoinQueriesGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlJoinQueriesGroupBlock.kt index f5fd9274..8790ef99 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlJoinQueriesGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlJoinQueriesGroupBlock.kt @@ -17,7 +17,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword.top import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithQuerySubGroupBlock import org.domaframework.doma.intellij.formatter.util.IndentType diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlSelectQueryGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlSelectQueryGroupBlock.kt index c61c9338..9bd39f23 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlSelectQueryGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlSelectQueryGroupBlock.kt @@ -56,6 +56,6 @@ class SqlSelectQueryGroupBlock( if (lastGroup is SqlWithQuerySubGroupBlock) return true if (lastBlock is SqlSubGroupBlock) return lastBlock.getChildBlocksDropLast().isNotEmpty() } - return true + return super.isSaveSpace(lastGroup) } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlTopQueryGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlTopQueryGroupBlock.kt index eb2defc9..f7e581bd 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlTopQueryGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlTopQueryGroupBlock.kt @@ -19,7 +19,7 @@ import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.common.util.TypeUtil import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateViewGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithQuerySubGroupBlock 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 index df8d9bb9..d34cb40d 100644 --- 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 @@ -18,8 +18,8 @@ package org.domaframework.doma.intellij.formatter.block.group.subgroup import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.word.SqlFunctionGroupBlock import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt index d02d95c8..f2a7e23c 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt @@ -23,8 +23,8 @@ import org.domaframework.doma.intellij.common.util.TypeUtil import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlRightPatternBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.conflict.SqlDoGroupBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlLateralGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateViewGroupBlock diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt index d22981f3..28bb6e8f 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt @@ -19,8 +19,8 @@ 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.comment.SqlBlockCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlJoinGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.condition.SqlConditionalExpressionGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.top.SqlJoinQueriesGroupBlock diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/word/SqlWordBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/word/SqlWordBlock.kt index 2ed5ccbc..5cf11e1b 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/word/SqlWordBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/word/SqlWordBlock.kt @@ -18,7 +18,7 @@ package org.domaframework.doma.intellij.formatter.block.word 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.expr.SqlElConditionLoopCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithCommonTableGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock import org.domaframework.doma.intellij.formatter.util.IndentType diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt index 0172989a..9fb75145 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt @@ -18,13 +18,11 @@ package org.domaframework.doma.intellij.formatter.builder import org.domaframework.doma.intellij.common.util.TypeUtil.isExpectedClassType import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock -import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlDefaultCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock -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.keyword.SqlKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock -import org.domaframework.doma.intellij.formatter.util.IndentType open class SqlBlockBuilder { private val updateDirectiveParentTypes = @@ -41,7 +39,7 @@ open class SqlBlockBuilder { private val groupTopNodeIndexHistory = mutableListOf() - private val commentBlocks = mutableListOf() + private val commentBlocks = mutableListOf() private val conditionOrLoopBlocks = mutableListOf() @@ -51,29 +49,21 @@ open class SqlBlockBuilder { groupTopNodeIndexHistory.add(block) } - fun addCommentBlock(block: SqlCommentBlock) { + fun addCommentBlock(block: SqlDefaultCommentBlock) { commentBlocks.add(block) } - fun updateCommentBlockIndent(baseIndent: SqlBlock) { + /** + * It becomes a child of the previous block, + * but the indentation is aligned with the next block. + */ + fun updateCommentBlockIndent(nextBlock: SqlBlock) { if (commentBlocks.isNotEmpty()) { var index = 0 commentBlocks - .filter { it.parentBlock == null } .forEach { block -> - if (block !is SqlElBlockCommentBlock) { - if (index == 0 && - baseIndent.parentBlock is SqlSubGroupBlock && - baseIndent.parentBlock?.childBlocks?.size == 1 - ) { - block.indent.indentLevel = IndentType.NONE - block.indent.indentLen = 1 - block.indent.groupIndentLen = 0 - } else { - block.setParentGroupBlock(baseIndent) - } - index++ - } + block.updateIndentLen(nextBlock) + index++ } commentBlocks.clear() } @@ -101,12 +91,7 @@ open class SqlBlockBuilder { } else { null } - // Prioritize previous condition loop block over keyword group -// if (prevConditionBlockGroup is SqlElConditionLoopCommentBlock) { -// setParentBlock = prevConditionBlockGroup -// } else if (prevConditionBlockGroup?.parentBlock is SqlElConditionLoopCommentBlock) { -// setParentBlock = prevConditionBlockGroup.parentBlock -// } else + if (lastGroup == nextBlock) { setParentBlock = if (isExpectedClassType( diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlCustomSpacingBuilder.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlCustomSpacingBuilder.kt index e0170c28..41e1a314 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlCustomSpacingBuilder.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlCustomSpacingBuilder.kt @@ -19,16 +19,13 @@ import com.intellij.formatting.ASTBlock import com.intellij.formatting.Block import com.intellij.formatting.Spacing import com.intellij.psi.tree.IElementType -import org.domaframework.doma.intellij.common.util.TypeUtil import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlRightPatternBlock import org.domaframework.doma.intellij.formatter.block.SqlWhitespaceBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElBlockCommentBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElBlockCommentBlock.SqlElCommentDirectiveType +import org.domaframework.doma.intellij.formatter.block.comment.SqlElBlockCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElBlockCommentBlock.SqlElCommentDirectiveType import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnBlock import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnDefinitionRawGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlDataTypeParamBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlParallelListBlock class SqlCustomSpacingBuilder { diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt index 27a1e43e..aeaaa6d6 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt @@ -17,11 +17,10 @@ package org.domaframework.doma.intellij.formatter.processor import org.domaframework.doma.intellij.common.util.TypeUtil.isExpectedClassType import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.SqlCommaBlock import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock import org.domaframework.doma.intellij.formatter.block.SqlRightPatternBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.conflict.SqlDoGroupBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnDefinitionRawGroupBlock import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnRawGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockUtil.kt index 25abe210..87d28730 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockUtil.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockUtil.kt @@ -28,11 +28,11 @@ import org.domaframework.doma.intellij.formatter.block.SqlCommaBlock import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElBlockCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.conflict.OnConflictKeywordType import org.domaframework.doma.intellij.formatter.block.conflict.SqlConflictClauseBlock import org.domaframework.doma.intellij.formatter.block.conflict.SqlDoGroupBlock -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.column.SqlColumnBlock import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnDefinitionRawGroupBlock import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnRawGroupBlock From b1f6d0468a3f3c5fea8ae6c2943fbdf82c8cfda5 Mon Sep 17 00:00:00 2001 From: xterao Date: Fri, 18 Jul 2025 13:40:27 +0900 Subject: [PATCH 05/11] Enhance SQL formatting for inline groups with improved parent group handling --- .../comment/SqlElConditionLoopCommentBlock.kt | 4 +- .../keyword/inline/SqlInlineGroupBlock.kt | 10 ++- .../inline/SqlInlineSecondGroupBlock.kt | 4 +- .../processor/SqlSetParentGroupProcessor.kt | 81 ++++++++++++------- 4 files changed, 67 insertions(+), 32 deletions(-) diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt index 45fb3258..89a56698 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt @@ -35,6 +35,8 @@ import org.domaframework.doma.intellij.formatter.block.expr.SqlElStaticFieldAcce import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnRawGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.inline.SqlInlineGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.inline.SqlInlineSecondGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertQueryGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder @@ -218,7 +220,7 @@ class SqlElConditionLoopCommentBlock( } val openConditionLoopDirectiveCount = getOpenDirectiveCount(parent) when (parent) { - is SqlKeywordGroupBlock, is SqlCommaBlock -> { + is SqlKeywordGroupBlock, is SqlCommaBlock, is SqlInlineGroupBlock, is SqlInlineSecondGroupBlock -> { return parent.indent.indentLen.plus(openConditionLoopDirectiveCount * 2) } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/inline/SqlInlineGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/inline/SqlInlineGroupBlock.kt index fc6af15c..4933b209 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/inline/SqlInlineGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/inline/SqlInlineGroupBlock.kt @@ -18,6 +18,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword.inline 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.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext @@ -47,7 +48,14 @@ open class SqlInlineGroupBlock( override fun buildChildren(): MutableList = mutableListOf() - override fun createBlockIndentLen(): Int = parentBlock?.indent?.groupIndentLen?.plus(1) ?: 1 + override fun createBlockIndentLen(): Int = + parentBlock?.let { parent -> + if (parent is SqlElConditionLoopCommentBlock) { + parent.indent.groupIndentLen + } else { + parent.indent.groupIndentLen.plus(1) + } + } ?: 1 override fun createGroupIndentLen(): Int = indent.indentLen.plus(getNodeText().length) } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/inline/SqlInlineSecondGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/inline/SqlInlineSecondGroupBlock.kt index 5fe3eb3e..60f63de5 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/inline/SqlInlineSecondGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/inline/SqlInlineSecondGroupBlock.kt @@ -18,6 +18,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword.inline 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.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext @@ -53,10 +54,11 @@ open class SqlInlineSecondGroupBlock( override fun createBlockIndentLen(): Int = parentBlock?.let { parent -> - // TODO:Customize indentation within an inline group if (isEndCase) { val diffTextLength = parent.getNodeText().length.minus(getNodeText().length) parent.indent.indentLen.plus(diffTextLength) + } else if (parent is SqlElConditionLoopCommentBlock) { + parent.indent.groupIndentLen } else { parent.indent.groupIndentLen.plus(1) } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt index aeaaa6d6..4ceb3bab 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt @@ -117,35 +117,8 @@ class SqlSetParentGroupProcessor( ) if (lastGroupBlock is SqlElConditionLoopCommentBlock) { - if (lastGroupBlock.parentBlock != null) { - setParentGroups(context) { history -> - return@setParentGroups lastGroupBlock - } - } else { - val history = blockBuilder.getGroupTopNodeIndexHistory() - val findParent = - history - .lastOrNull { - it.indent.indentLevel < childBlock.indent.indentLevel || - (it is SqlElConditionLoopCommentBlock && it.parentBlock != null) - } - // Search for keyword groups with a level lower than or equal to the current level, - // or conditional directives that already have a parent assigned. - if (findParent is SqlElConditionLoopCommentBlock) { - // Set the parent of the most recent conditional directive to the current node. - lastGroupBlock.setParentGroupBlock(findParent) - setParentGroups(context) { history -> - return@setParentGroups lastGroupBlock - } - } - if (findParent !is SqlElConditionLoopCommentBlock) { - // If a keyword group with a level lower than or equal to the current level is found, - // set that keyword group as the parent, and set the parent of the most recent conditional directive to the current node. - setParentGroups(context) { history -> - return@setParentGroups findParent - } - lastGroupBlock.setParentGroupBlock(childBlock) - } + updateParentGroupLastConditionLoop(lastGroupBlock, context, childBlock) { + it.indent.indentLevel < childBlock.indent.indentLevel } return } @@ -319,6 +292,15 @@ class SqlSetParentGroupProcessor( } return } + + val lastGroupBlock = blockBuilder.getLastGroupTopNodeIndexHistory() + if (lastGroupBlock is SqlElConditionLoopCommentBlock) { + updateParentGroupLastConditionLoop(lastGroupBlock, context, childBlock) { + it.indent.indentLevel == IndentType.INLINE_SECOND + } + return + } + val inlineSecondIndex = blockBuilder.getGroupTopNodeIndex { block -> block.indent.indentLevel == IndentType.INLINE_SECOND @@ -331,6 +313,47 @@ class SqlSetParentGroupProcessor( ) } + /** + * Updates the parent of the last conditional directive block and sets the parent of the current block. + */ + private fun updateParentGroupLastConditionLoop( + lastGroupBlock: SqlElConditionLoopCommentBlock, + context: SetParentContext, + childBlock: SqlBlock, + findDefaultParent: (SqlBlock) -> Boolean, + ) { + if (lastGroupBlock.parentBlock != null) { + setParentGroups(context) { history -> + return@setParentGroups lastGroupBlock + } + } else { + val history = blockBuilder.getGroupTopNodeIndexHistory() + val findParent = + history + .lastOrNull { block -> + findDefaultParent(block) || + (block is SqlElConditionLoopCommentBlock && block.parentBlock != null) + } + // Search for keyword groups with a level lower than or equal to the current level, + // or conditional directives that already have a parent assigned. + if (findParent is SqlElConditionLoopCommentBlock) { + // Set the parent of the most recent conditional directive to the current node. + lastGroupBlock.setParentGroupBlock(findParent) + setParentGroups(context) { history -> + return@setParentGroups lastGroupBlock + } + } + if (findParent !is SqlElConditionLoopCommentBlock) { + // If a keyword group with a level lower than or equal to the current level is found, + // set that keyword group as the parent, and set the parent of the most recent conditional directive to the current node. + setParentGroups(context) { history -> + return@setParentGroups findParent + } + lastGroupBlock.setParentGroupBlock(childBlock) + } + } + } + fun updateConditionLoopCommentBlockParent( lastGroupBlock: SqlBlock, childBlock: SqlElConditionLoopCommentBlock, From a42e91b2712f303ed49f7844eb945deb1129c68c Mon Sep 17 00:00:00 2001 From: xterao Date: Fri, 18 Jul 2025 13:41:13 +0900 Subject: [PATCH 06/11] Add SQL formatting test for select case with nested conditions --- .../doma/intellij/formatter/SqlFormatterTest.kt | 4 ++++ .../sql/formatter/SelectCaseEndWithCondition.sql | 9 +++++++++ .../formatter/SelectCaseEndWithCondition_format.sql | 11 +++++++++++ .../sql/formatter/UpdateBindVariable_format.sql | 2 +- 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/test/testData/sql/formatter/SelectCaseEndWithCondition.sql create mode 100644 src/test/testData/sql/formatter/SelectCaseEndWithCondition_format.sql 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 ec63a3ac..c34ef990 100644 --- a/src/test/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatterTest.kt +++ b/src/test/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatterTest.kt @@ -170,6 +170,10 @@ class SqlFormatterTest : BasePlatformTestCase() { formatSqlFile("NestedDirectives.sql", "NestedDirectives$formatDataPrefix.sql") } + fun testSelectCaseEndWithConditionFormatter() { + formatSqlFile("SelectCaseEndWithCondition.sql", "SelectCaseEndWithCondition$formatDataPrefix.sql") + } + private fun formatSqlFile( beforeFile: String, afterFile: String, diff --git a/src/test/testData/sql/formatter/SelectCaseEndWithCondition.sql b/src/test/testData/sql/formatter/SelectCaseEndWithCondition.sql new file mode 100644 index 00000000..799b559c --- /dev/null +++ b/src/test/testData/sql/formatter/SelectCaseEndWithCondition.sql @@ -0,0 +1,9 @@ +Select case when div = 'A' then 'AAA' +/*%if addCondition*/ + /*%if conditionType == 1 */when div = 'B' then 'BBB1' +/*%elseif conditionType == 2 */ +when div = 'B' then 'BBB2' +/*%end*/ +/*%end*/ + else 'CCC' end as divName +from users \ No newline at end of file diff --git a/src/test/testData/sql/formatter/SelectCaseEndWithCondition_format.sql b/src/test/testData/sql/formatter/SelectCaseEndWithCondition_format.sql new file mode 100644 index 00000000..38c3ab7a --- /dev/null +++ b/src/test/testData/sql/formatter/SelectCaseEndWithCondition_format.sql @@ -0,0 +1,11 @@ +SELECT CASE WHEN div = 'A' THEN 'AAA' + /*%if addCondition*/ + /*%if conditionType == 1 */ + WHEN div = 'B' THEN 'BBB1' + /*%elseif conditionType == 2 */ + WHEN div = 'B' THEN 'BBB2' + /*%end*/ + /*%end*/ + ELSE 'CCC' + END AS divName + FROM users diff --git a/src/test/testData/sql/formatter/UpdateBindVariable_format.sql b/src/test/testData/sql/formatter/UpdateBindVariable_format.sql index d5fd4d4b..7443393a 100644 --- a/src/test/testData/sql/formatter/UpdateBindVariable_format.sql +++ b/src/test/testData/sql/formatter/UpdateBindVariable_format.sql @@ -3,6 +3,6 @@ UPDATE /*# tableName */ , X2 = 2 , X3 = 3 /*%for entity : entities */ - , /*# entity.itemIdentifier */= /* entity.value */'abc' + , /*# entity.itemIdentifier */ = /* entity.value */'abc' /*%end*/ WHERE X = /* reportId */1 From 7a24889ad467043fa0943fc51c1c17bb0f103be1 Mon Sep 17 00:00:00 2001 From: xterao Date: Fri, 18 Jul 2025 16:06:18 +0900 Subject: [PATCH 07/11] Refactor SQL formatting logic to enhance handling of nested condition loops and improve spacing for various SQL constructs --- .../doma/intellij/formatter/block/SqlBlock.kt | 13 ++++++ .../intellij/formatter/block/SqlFileBlock.kt | 21 +++++---- .../comment/SqlElConditionLoopCommentBlock.kt | 14 +++--- .../group/keyword/SqlKeywordGroupBlock.kt | 5 ++- .../processor/SqlSetParentGroupProcessor.kt | 41 +++++++++++------ .../intellij/formatter/util/CommaRawUtil.kt | 45 +++++++++++++++++++ .../intellij/formatter/util/SqlBlockUtil.kt | 16 +------ .../intellij/formatter/util/SqlKeywordUtil.kt | 1 + .../sql/formatter/NestedDirectives_format.sql | 5 +-- 9 files changed, 112 insertions(+), 49 deletions(-) create mode 100644 src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CommaRawUtil.kt 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 3484447c..e40857f3 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 @@ -25,11 +25,14 @@ import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlDefaultCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock +import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlKeywordUtil import org.domaframework.doma.intellij.psi.SqlTypes open class SqlBlock( @@ -129,6 +132,16 @@ open class SqlBlock( (prevBlock.conditionType.isElse() || prevBlock.conditionType.isEnd()) || parent.childBlocks.dropLast(1).isEmpty() } + if (parent is SqlNewGroupBlock) { + val prevWord = prevBlocks.lastOrNull { it !is SqlCommentBlock } + if (SqlKeywordUtil.isSetLineKeyword(getNodeText(), parent.getNodeText()) || + SqlKeywordUtil.isSetLineKeyword(getNodeText(), prevWord?.getNodeText() ?: "") + ) { + return false + } + return childBlocks.lastOrNull() is SqlElConditionLoopCommentBlock || + prevBlocks.lastOrNull() is SqlElConditionLoopCommentBlock + } } return false } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt index 941123cb..1906eecd 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt @@ -27,7 +27,6 @@ import com.intellij.lang.ASTNode import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.common.util.TypeUtil -import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlDefaultCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlElBlockCommentBlock @@ -534,14 +533,6 @@ class SqlFileBlock( return SqlCustomSpacingBuilder().getSpacing(childBlock2) } - if (childBlock1 is SqlWhitespaceBlock) { - when (childBlock2) { - is SqlBlockCommentBlock, is SqlLineCommentBlock, is SqlNewGroupBlock -> { - return SqlCustomSpacingBuilder().getSpacing(childBlock2) - } - } - } - if (childBlock2 is SqlNewGroupBlock) { if (childBlock1 is SqlSubGroupBlock && childBlock2.indent.indentLevel == IndentType.ATTACHED) { return SqlCustomSpacingBuilder.nonSpacing @@ -583,6 +574,18 @@ class SqlFileBlock( ?.let { return it } } + // First apply spacing logic for blocks under specific conditions, + // then execute the general spacing logic for post-line-break blocks at the end. + if (childBlock1 is SqlWhitespaceBlock) { + return when (childBlock2) { + is SqlDefaultCommentBlock, is SqlNewGroupBlock -> { + SqlCustomSpacingBuilder().getSpacing(childBlock2) + } + + else -> SqlCustomSpacingBuilder().getSpacing(childBlock2) + } + } + val spacing: Spacing? = customSpacingBuilder?.getCustomSpacing(childBlock1, childBlock2) return spacing ?: spacingBuilder.getSpacing(this, childBlock1, childBlock2) } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt index 89a56698..4f8f5b9c 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt @@ -25,7 +25,7 @@ import com.intellij.psi.util.elementType import org.domaframework.doma.intellij.common.util.TypeUtil import org.domaframework.doma.intellij.extension.expr.isConditionOrLoopDirective import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.SqlCommaBlock +import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock import org.domaframework.doma.intellij.formatter.block.SqlOperationBlock import org.domaframework.doma.intellij.formatter.block.SqlRightPatternBlock import org.domaframework.doma.intellij.formatter.block.SqlUnknownBlock @@ -35,8 +35,6 @@ import org.domaframework.doma.intellij.formatter.block.expr.SqlElStaticFieldAcce import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnRawGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.inline.SqlInlineGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.inline.SqlInlineSecondGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertQueryGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder @@ -200,10 +198,13 @@ class SqlElConditionLoopCommentBlock( override fun isLeaf(): Boolean = false override fun isSaveSpace(lastGroup: SqlBlock?): Boolean { + if (conditionType.isEnd() || conditionType.isElse()) { + return true + } if (lastGroup is SqlSubGroupBlock) { return lastGroup.childBlocks.dropLast(1).isNotEmpty() } - return true + return lastGroup?.childBlocks?.any { it !is SqlKeywordBlock && it !is SqlKeywordGroupBlock } == true } /** @@ -220,10 +221,6 @@ class SqlElConditionLoopCommentBlock( } val openConditionLoopDirectiveCount = getOpenDirectiveCount(parent) when (parent) { - is SqlKeywordGroupBlock, is SqlCommaBlock, is SqlInlineGroupBlock, is SqlInlineSecondGroupBlock -> { - return parent.indent.indentLen.plus(openConditionLoopDirectiveCount * 2) - } - is SqlSubGroupBlock -> { val parentGroupIndentLen = parent.indent.groupIndentLen val grand = parent.parentBlock @@ -266,6 +263,7 @@ class SqlElConditionLoopCommentBlock( return parent.indent.indentLen.plus(2) } } + else -> return parent.indent.indentLen.plus(openConditionLoopDirectiveCount * 2) } } return 0 diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt index dba66ccd..efc413c4 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt @@ -44,6 +44,7 @@ open class SqlKeywordGroupBlock( listOf( SqlKeywordBlock::class, SqlKeywordGroupBlock::class, + SqlElConditionLoopCommentBlock::class, ) if (lastChild == null || @@ -55,7 +56,9 @@ open class SqlKeywordGroupBlock( ) { topKeywordBlocks.add(block) } else { - canAddTopKeyword = false + if (block !is SqlElConditionLoopCommentBlock) { + canAddTopKeyword = false + } } indent.groupIndentLen = createGroupIndentLen() diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt index 4ceb3bab..881c915f 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt @@ -64,12 +64,19 @@ class SqlSetParentGroupProcessor( * Sets the parent of the latest group block and registers itself as a child element. */ fun updateGroupBlockParentAndAddGroup(childBlock: SqlBlock) { - setParentGroups( + val context = SetParentContext( childBlock, blockBuilder, - ), - ) { history -> + ) + val lastGroup = blockBuilder.getLastGroupTopNodeIndexHistory() + if (lastGroup is SqlElConditionLoopCommentBlock) { + updateParentGroupLastConditionLoop(lastGroup, context) { block -> + block.indent.indentLevel < childBlock.indent.indentLevel + } + return + } + setParentGroups(context) { history -> return@setParentGroups history.lastOrNull() } } @@ -91,7 +98,7 @@ class SqlSetParentGroupProcessor( /** * Registers itself as a child element in the same block as the parent of the last group at the time of processing. */ - fun updateGroupBlockLastGroupParentAddGroup( + private fun updateGroupBlockLastGroupParentAddGroup( lastGroupBlock: SqlBlock, childBlock: SqlBlock, ) { @@ -117,7 +124,7 @@ class SqlSetParentGroupProcessor( ) if (lastGroupBlock is SqlElConditionLoopCommentBlock) { - updateParentGroupLastConditionLoop(lastGroupBlock, context, childBlock) { + updateParentGroupLastConditionLoop(lastGroupBlock, context) { it.indent.indentLevel < childBlock.indent.indentLevel } return @@ -257,15 +264,23 @@ class SqlSetParentGroupProcessor( listOf( SqlColumnRawGroupBlock::class, ) - if (isExpectedClassType(expectedTypes, lastGroupBlock)) { - blockBuilder.removeLastGroupTopNodeIndexHistory() - } - setParentGroups( + val context = SetParentContext( childBlock, blockBuilder, - ), - ) { history -> + ) + + if (lastGroupBlock is SqlElConditionLoopCommentBlock) { + updateParentGroupLastConditionLoop(lastGroupBlock, context) { + it.indent.indentLevel < childBlock.indent.indentLevel + } + return + } + + if (isExpectedClassType(expectedTypes, lastGroupBlock)) { + blockBuilder.removeLastGroupTopNodeIndexHistory() + } + setParentGroups(context) { history -> return@setParentGroups history .lastOrNull { it.indent.indentLevel < childBlock.indent.indentLevel } } @@ -295,7 +310,7 @@ class SqlSetParentGroupProcessor( val lastGroupBlock = blockBuilder.getLastGroupTopNodeIndexHistory() if (lastGroupBlock is SqlElConditionLoopCommentBlock) { - updateParentGroupLastConditionLoop(lastGroupBlock, context, childBlock) { + updateParentGroupLastConditionLoop(lastGroupBlock, context) { it.indent.indentLevel == IndentType.INLINE_SECOND } return @@ -319,9 +334,9 @@ class SqlSetParentGroupProcessor( private fun updateParentGroupLastConditionLoop( lastGroupBlock: SqlElConditionLoopCommentBlock, context: SetParentContext, - childBlock: SqlBlock, findDefaultParent: (SqlBlock) -> Boolean, ) { + val childBlock = context.childBlock if (lastGroupBlock.parentBlock != null) { setParentGroups(context) { history -> return@setParentGroups lastGroupBlock diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CommaRawUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CommaRawUtil.kt new file mode 100644 index 00000000..bc8f2c4c --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CommaRawUtil.kt @@ -0,0 +1,45 @@ +package org.domaframework.doma.intellij.formatter.util + +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.SqlCommaBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock +import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnRawGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithCommonTableGroupBlock + +object CommaRawUtil { + fun getCommaBlock( + lastGroup: SqlBlock?, + child: ASTNode, + sqlBlockFormattingCtx: SqlBlockFormattingContext, + ): SqlBlock = + if (lastGroup is SqlElConditionLoopCommentBlock) { + if (lastGroup.parentBlock == null) { + getSqlCommaBlock(lastGroup.tempParentBlock, child, sqlBlockFormattingCtx) + } else { + getSqlCommaBlock(lastGroup.parentBlock, child, sqlBlockFormattingCtx) + } + } else { + getSqlCommaBlock(lastGroup, child, sqlBlockFormattingCtx) + } + + private fun getSqlCommaBlock( + lastGroup: SqlBlock?, + child: ASTNode, + sqlBlockFormattingCtx: SqlBlockFormattingContext, + ): SqlBlock = + when (lastGroup) { + is SqlColumnRawGroupBlock, is SqlKeywordGroupBlock -> { + if (lastGroup.indent.indentLevel == IndentType.SECOND) { + SqlCommaBlock(child, sqlBlockFormattingCtx) + } else { + SqlColumnRawGroupBlock(child, sqlBlockFormattingCtx) + } + } + + is SqlWithCommonTableGroupBlock -> SqlWithCommonTableGroupBlock(child, sqlBlockFormattingCtx) + + else -> SqlCommaBlock(child, sqlBlockFormattingCtx) + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockUtil.kt index 87d28730..5179fed7 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockUtil.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockUtil.kt @@ -24,7 +24,6 @@ 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.SqlCommaBlock import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock @@ -35,7 +34,6 @@ import org.domaframework.doma.intellij.formatter.block.conflict.SqlConflictClaus import org.domaframework.doma.intellij.formatter.block.conflict.SqlDoGroupBlock import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnBlock import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnDefinitionRawGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnRawGroupBlock 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.SqlLateralGroupBlock @@ -393,19 +391,7 @@ class SqlBlockUtil( .getColumnRawGroup(lastGroup, child, sqlBlockFormattingCtx) ?.let { return it } - return when (lastGroup) { - is SqlColumnRawGroupBlock, is SqlKeywordGroupBlock -> { - if (lastGroup.indent.indentLevel == IndentType.SECOND) { - SqlCommaBlock(child, sqlBlockFormattingCtx) - } else { - SqlColumnRawGroupBlock(child, sqlBlockFormattingCtx) - } - } - - is SqlWithCommonTableGroupBlock -> SqlWithCommonTableGroupBlock(child, sqlBlockFormattingCtx) - - else -> SqlCommaBlock(child, sqlBlockFormattingCtx) - } + return CommaRawUtil.getCommaBlock(lastGroup, child, sqlBlockFormattingCtx) } fun getWordBlock( diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlKeywordUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlKeywordUtil.kt index 84aa3f27..7aef2483 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlKeywordUtil.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlKeywordUtil.kt @@ -313,6 +313,7 @@ class SqlKeywordUtil { "update" to setOf("do"), "set" to setOf("by", "cycle"), "order" to setOf("partition", "by"), + "select" to setOf("if", "exists"), ) fun isSetLineKeyword( diff --git a/src/test/testData/sql/formatter/NestedDirectives_format.sql b/src/test/testData/sql/formatter/NestedDirectives_format.sql index 075d86ae..ad1d97ac 100644 --- a/src/test/testData/sql/formatter/NestedDirectives_format.sql +++ b/src/test/testData/sql/formatter/NestedDirectives_format.sql @@ -4,15 +4,14 @@ SELECT e.id FROM employee e /*%if includesDepartment */ LEFT JOIN department d - ON e.department_id = d.id + ON e.department_id = d.id /*%if includeDepartmentDetails */ LEFT JOIN department_detail dd ON d.id = dd.department_id /*%end */ /*%end */ WHERE 1 = 1 - ORDER BY - /*%if sortConditions != null && !sortConditions.isEmpty() */ -- IF1 + ORDER BY /*%if sortConditions != null && !sortConditions.isEmpty() */ -- IF1 /*%for sort : sortConditions */ -- IF2 /*%if sort.field == "name" */ -- IF3 e.name From 193f5708dcf0a4b3365da35e8201b82fd942a2e0 Mon Sep 17 00:00:00 2001 From: xterao Date: Fri, 18 Jul 2025 18:39:10 +0900 Subject: [PATCH 08/11] Fixed the indent adjustment method for normal comments --- .../doma/intellij/formatter/block/SqlBlock.kt | 16 ++++++++---- .../intellij/formatter/block/SqlFileBlock.kt | 12 +++++++-- .../formatter/block/SqlRightPatternBlock.kt | 4 +-- .../block/comment/SqlDefaultCommentBlock.kt | 26 ++++++++++++++++--- .../comment/SqlElConditionLoopCommentBlock.kt | 5 ++-- .../group/subgroup/SqlFunctionParamBlock.kt | 11 +++----- .../block/group/subgroup/SqlSubGroupBlock.kt | 2 -- .../group/subgroup/SqlSubQueryGroupBlock.kt | 5 ++-- .../block/word/SqlFunctionGroupBlock.kt | 5 ++-- .../formatter/builder/SqlBlockBuilder.kt | 12 ++++----- .../processor/SqlSetParentGroupProcessor.kt | 9 +++---- .../intellij/formatter/util/CommaRawUtil.kt | 15 +++++++++++ 12 files changed, 80 insertions(+), 42 deletions(-) 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 e40857f3..3135230a 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 @@ -24,16 +24,15 @@ 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.comment.SqlBlockCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlDefaultCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock -import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.formatter.util.SqlKeywordUtil import org.domaframework.doma.intellij.psi.SqlTypes +import org.jetbrains.kotlin.psi.psiUtil.startOffset open class SqlBlock( node: ASTNode, @@ -69,7 +68,7 @@ open class SqlBlock( fun getChildrenTextLen(): Int = childBlocks.sumOf { child -> val children = - child.childBlocks.filter { it !is SqlLineCommentBlock && it !is SqlBlockCommentBlock } + child.childBlocks.filter { it !is SqlDefaultCommentBlock } if (children.isNotEmpty()) { child .getChildrenTextLen() @@ -90,7 +89,7 @@ open class SqlBlock( ): List { val children = childBlocks.dropLast(dropIndex) if (skipCommentBlock) { - return children.filter { it !is SqlLineCommentBlock && it !is SqlBlockCommentBlock } + return children.filter { it !is SqlDefaultCommentBlock } } return children } @@ -132,6 +131,7 @@ open class SqlBlock( (prevBlock.conditionType.isElse() || prevBlock.conditionType.isEnd()) || parent.childBlocks.dropLast(1).isEmpty() } + // Checks for non-breaking keyword combinations, ignoring comment blocks if (parent is SqlNewGroupBlock) { val prevWord = prevBlocks.lastOrNull { it !is SqlCommentBlock } if (SqlKeywordUtil.isSetLineKeyword(getNodeText(), parent.getNodeText()) || @@ -139,8 +139,14 @@ open class SqlBlock( ) { return false } + // Breaks a line if it is a child of itself or preceded by a condition/loop directive return childBlocks.lastOrNull() is SqlElConditionLoopCommentBlock || - prevBlocks.lastOrNull() is SqlElConditionLoopCommentBlock + ( + prevBlocks.lastOrNull() is SqlElConditionLoopCommentBlock && + prevBlocks + .last() + .node.psi.startOffset > parent.node.psi.startOffset + ) } } return false diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt index 1906eecd..577f99c5 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt @@ -51,7 +51,9 @@ import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGrou import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock import org.domaframework.doma.intellij.formatter.block.other.SqlEscapeBlock import org.domaframework.doma.intellij.formatter.block.other.SqlOtherBlock +import org.domaframework.doma.intellij.formatter.block.word.SqlAliasBlock import org.domaframework.doma.intellij.formatter.block.word.SqlFunctionGroupBlock +import org.domaframework.doma.intellij.formatter.block.word.SqlTableBlock import org.domaframework.doma.intellij.formatter.block.word.SqlWordBlock import org.domaframework.doma.intellij.formatter.builder.SqlBlockBuilder import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder @@ -314,6 +316,8 @@ class SqlFileBlock( return } + if (childBlock is SqlDefaultCommentBlock) return + when (childBlock) { is SqlKeywordGroupBlock -> { parentSetProcessor.updateKeywordGroupBlockParentAndAddGroup( @@ -364,7 +368,7 @@ class SqlFileBlock( ) } - is SqlWordBlock, is SqlOtherBlock, is SqlDefaultCommentBlock -> { + is SqlWordBlock, is SqlOtherBlock -> { parentSetProcessor.updateGroupBlockParentAndAddGroup( childBlock, ) @@ -546,7 +550,7 @@ class SqlFileBlock( is SqlDataTypeParamBlock, is SqlFunctionParamBlock -> return SqlCustomSpacingBuilder.nonSpacing - else -> return SqlCustomSpacingBuilder.normalSpacing + // else -> return SqlCustomSpacingBuilder.normalSpacing } } @@ -586,6 +590,10 @@ class SqlFileBlock( } } + if (childBlock1 is SqlTableBlock || childBlock1 is SqlAliasBlock) { + return SqlCustomSpacingBuilder.normalSpacing + } + val spacing: Spacing? = customSpacingBuilder?.getCustomSpacing(childBlock1, childBlock2) return spacing ?: spacingBuilder.getSpacing(this, childBlock1, childBlock2) } 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 deddd73b..de3255ca 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 @@ -110,7 +110,7 @@ open class SqlRightPatternBlock( INDENT_EXPECTED_TYPES, parent, ) || - parent.childBlocks.firstOrNull() is SqlValuesGroupBlock + parent.childBlocks.any { it is SqlValuesGroupBlock } ) { preSpaceRight = true return @@ -179,7 +179,7 @@ open class SqlRightPatternBlock( override fun isSaveSpace(lastGroup: SqlBlock?): Boolean { parentBlock?.let { parent -> if (isExpectedClassType(NEW_LINE_EXPECTED_TYPES, parent) || - parent.childBlocks.firstOrNull() is SqlValuesGroupBlock + parent.childBlocks.any { it is SqlValuesGroupBlock } ) { lineBreakAndSpacingType = if (preSpaceRight) { diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlDefaultCommentBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlDefaultCommentBlock.kt index 96ef29f9..07eba562 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlDefaultCommentBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlDefaultCommentBlock.kt @@ -19,24 +19,42 @@ import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import com.intellij.psi.util.PsiTreeUtil import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.SqlFileBlock +import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext abstract class SqlDefaultCommentBlock( node: ASTNode, context: SqlBlockFormattingContext, ) : SqlCommentBlock(node, context) { + /** + * If this block is the last element, the indentation update process is not called, + * so set the default indentation to 1. + */ + override val indent = + ElementIndent( + IndentType.NONE, + 1, + 1, + ) + override fun buildChildren(): MutableList = mutableListOf() override fun isLeaf(): Boolean = true /** - * When the next element block is determined, update the indent to align it with the element below. + * When the next element block is determined, + * update the indent to align it with the element below. */ - fun updateIndentLen(baseBlock: SqlBlock) { + fun updateIndentLen( + baseBlock: SqlBlock, + groupBlockCount: Int, + ) { indent.indentLen = - if (parentBlock is SqlFileBlock || isSaveSpace(parentBlock)) { + if (isSaveSpace(parentBlock)) { baseBlock.indent.indentLen + } else if (groupBlockCount <= 2) { + // If it is the top of the file, the indent number should be 0. + 0 } else { 1 } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt index 4f8f5b9c..7084ecbb 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt @@ -25,7 +25,6 @@ import com.intellij.psi.util.elementType import org.domaframework.doma.intellij.common.util.TypeUtil import org.domaframework.doma.intellij.extension.expr.isConditionOrLoopDirective import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock import org.domaframework.doma.intellij.formatter.block.SqlOperationBlock import org.domaframework.doma.intellij.formatter.block.SqlRightPatternBlock import org.domaframework.doma.intellij.formatter.block.SqlUnknownBlock @@ -204,7 +203,7 @@ class SqlElConditionLoopCommentBlock( if (lastGroup is SqlSubGroupBlock) { return lastGroup.childBlocks.dropLast(1).isNotEmpty() } - return lastGroup?.childBlocks?.any { it !is SqlKeywordBlock && it !is SqlKeywordGroupBlock } == true + return true } /** @@ -275,7 +274,7 @@ class SqlElConditionLoopCommentBlock( val conditionLoopDirectives: List = parent .childBlocks - .mapNotNull { it as? SqlElConditionLoopCommentBlock } + .filterIsInstance() .filter { it.conditionEnd == null } val startDirectives = conditionLoopDirectives.count { it.conditionType.isStartDirective() } 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 index d34cb40d..e9adf8a2 100644 --- 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 @@ -17,9 +17,8 @@ package org.domaframework.doma.intellij.formatter.block.group.subgroup import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlDefaultCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock -import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock import org.domaframework.doma.intellij.formatter.block.word.SqlFunctionGroupBlock import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext @@ -65,9 +64,8 @@ class SqlFunctionParamBlock( val children = prevChildren?.dropLast(1)?.filter { - it !is SqlLineCommentBlock && - it !is SqlBlockCommentBlock && - it.node != SqlTypes.DOT + it !is SqlDefaultCommentBlock + it.node != SqlTypes.DOT } children?.let { prevList -> return prevList @@ -89,8 +87,7 @@ class SqlFunctionParamBlock( val prevChildrenDropLast = prevChildren?.dropLast(1)?.filter { - it !is SqlLineCommentBlock && - it !is SqlBlockCommentBlock && + it !is SqlDefaultCommentBlock && it.node.elementType != SqlTypes.DOT } ?: emptyList() diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt index f2a7e23c..53de2a1b 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubGroupBlock.kt @@ -102,8 +102,6 @@ abstract class SqlSubGroupBlock( override fun isLeaf(): Boolean = true - open fun endGroup() {} - override fun createBlockIndentLen(): Int { parentBlock?.let { parent -> if (parent is SqlElConditionLoopCommentBlock) return parent.indent.groupIndentLen diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt index 28bb6e8f..19157d16 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt @@ -18,9 +18,8 @@ package org.domaframework.doma.intellij.formatter.block.group.subgroup 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.comment.SqlBlockCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlDefaultCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock -import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlJoinGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.condition.SqlConditionalExpressionGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.top.SqlJoinQueriesGroupBlock @@ -56,7 +55,7 @@ open class SqlSubQueryGroupBlock( is SqlJoinQueriesGroupBlock -> return parent.indent.indentLen is SqlJoinGroupBlock -> return parent.indent.groupIndentLen.plus(1) else -> { - val children = prevChildren?.filter { it !is SqlLineCommentBlock && it !is SqlBlockCommentBlock } + val children = prevChildren?.filter { it !is SqlDefaultCommentBlock } return children ?.dropLast(1) ?.sumOf { prev -> diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/word/SqlFunctionGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/word/SqlFunctionGroupBlock.kt index 91fe6cbb..2e047a9e 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/word/SqlFunctionGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/word/SqlFunctionGroupBlock.kt @@ -17,8 +17,7 @@ package org.domaframework.doma.intellij.formatter.block.word import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock -import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlDefaultCommentBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlFunctionParamBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext @@ -40,7 +39,7 @@ class SqlFunctionGroupBlock( override fun createBlockIndentLen(): Int { parentBlock?.let { parent -> - val children = prevChildren.dropLast(1).filter { it !is SqlLineCommentBlock && it !is SqlBlockCommentBlock } + val children = prevChildren.dropLast(1).filter { it !is SqlDefaultCommentBlock } val prevBlocksLength = children .sumOf { prev -> diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt index 9fb75145..19014d42 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt @@ -17,18 +17,15 @@ package org.domaframework.doma.intellij.formatter.builder import org.domaframework.doma.intellij.common.util.TypeUtil.isExpectedClassType import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlDefaultCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock -import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock open class SqlBlockBuilder { private val updateDirectiveParentTypes = listOf( - SqlLineCommentBlock::class, - SqlBlockCommentBlock::class, + SqlDefaultCommentBlock::class, ) private val originalConditionLoopDirectiveParentType = @@ -58,11 +55,14 @@ open class SqlBlockBuilder { * but the indentation is aligned with the next block. */ fun updateCommentBlockIndent(nextBlock: SqlBlock) { - if (commentBlocks.isNotEmpty()) { + if (commentBlocks.isNotEmpty() && + nextBlock.parentBlock != null || + groupTopNodeIndexHistory.size <= 2 + ) { var index = 0 commentBlocks .forEach { block -> - block.updateIndentLen(nextBlock) + block.updateIndentLen(nextBlock, groupTopNodeIndexHistory.size) index++ } commentBlocks.clear() diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt index 881c915f..7f637bf5 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt @@ -19,6 +19,7 @@ import org.domaframework.doma.intellij.common.util.TypeUtil.isExpectedClassType import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock import org.domaframework.doma.intellij.formatter.block.SqlRightPatternBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlDefaultCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock import org.domaframework.doma.intellij.formatter.block.conflict.SqlDoGroupBlock import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnDefinitionRawGroupBlock @@ -426,10 +427,6 @@ class SqlSetParentGroupProcessor( return@setParentGroups history[paramIndex] } - if (childBlock.parentBlock is SqlSubGroupBlock) { - (childBlock.parentBlock as SqlSubGroupBlock).endGroup() - } - if (blockBuilder.getGroupTopNodeIndexHistory()[paramIndex] is SqlWithQuerySubGroupBlock) { val withCommonBlockIndex = blockBuilder.getGroupTopNodeIndex { block -> @@ -475,6 +472,8 @@ class SqlSetParentGroupProcessor( val targetChildBlock = context.childBlock + if (targetChildBlock is SqlDefaultCommentBlock) return + // The parent block for SqlElConditionLoopCommentBlock will be set later if (targetChildBlock is SqlElConditionLoopCommentBlock && targetChildBlock.conditionType.isStartDirective()) { targetChildBlock.tempParentBlock = parentGroup @@ -492,9 +491,9 @@ class SqlSetParentGroupProcessor( ) ) { context.blockBuilder.addGroupTopNodeIndexHistory(targetChildBlock) - context.blockBuilder.updateCommentBlockIndent(targetChildBlock) } + context.blockBuilder.updateCommentBlockIndent(targetChildBlock) // Set parent-child relationship and indent for preceding comment at beginning of block group context.blockBuilder.updateConditionLoopBlockIndent(targetChildBlock) } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CommaRawUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CommaRawUtil.kt index bc8f2c4c..41eebcad 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CommaRawUtil.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CommaRawUtil.kt @@ -1,3 +1,18 @@ +/* + * 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.util import com.intellij.lang.ASTNode From f70c6cd30a111f3ec2ac936e1e4c77679f6514cb Mon Sep 17 00:00:00 2001 From: xterao Date: Fri, 18 Jul 2025 18:39:47 +0900 Subject: [PATCH 09/11] Fix conditional directive test cases after keywords --- src/test/testData/sql/formatter/NestedDirectives_format.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/testData/sql/formatter/NestedDirectives_format.sql b/src/test/testData/sql/formatter/NestedDirectives_format.sql index ad1d97ac..609db932 100644 --- a/src/test/testData/sql/formatter/NestedDirectives_format.sql +++ b/src/test/testData/sql/formatter/NestedDirectives_format.sql @@ -11,7 +11,8 @@ SELECT e.id /*%end */ /*%end */ WHERE 1 = 1 - ORDER BY /*%if sortConditions != null && !sortConditions.isEmpty() */ -- IF1 + ORDER BY + /*%if sortConditions != null && !sortConditions.isEmpty() */ -- IF1 /*%for sort : sortConditions */ -- IF2 /*%if sort.field == "name" */ -- IF3 e.name From fb4e727766429f1721598f61030bfe1c83397a43 Mon Sep 17 00:00:00 2001 From: xterao Date: Fri, 18 Jul 2025 19:10:56 +0900 Subject: [PATCH 10/11] Refactor SQL formatting logic to improve readability and handling of condition loop comments --- .../doma/intellij/formatter/block/SqlBlock.kt | 100 +++--- .../intellij/formatter/block/SqlFileBlock.kt | 7 +- .../comment/SqlElConditionLoopCommentBlock.kt | 5 + .../formatter/processor/SqlPostProcessor.kt | 45 ++- .../processor/SqlSetParentGroupProcessor.kt | 326 ++++++++++-------- .../intellij/formatter/util/CommaRawUtil.kt | 66 +++- .../sql/formatter/NestedDirectives.sql | 5 +- .../sql/formatter/NestedDirectives_format.sql | 4 + 8 files changed, 329 insertions(+), 229 deletions(-) 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 3135230a..0fdd4109 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 @@ -65,23 +65,21 @@ open class SqlBlock( open val childBlocks = mutableListOf() open var prevBlocks = emptyList() - fun getChildrenTextLen(): Int = - childBlocks.sumOf { child -> - val children = - child.childBlocks.filter { it !is SqlDefaultCommentBlock } - if (children.isNotEmpty()) { - child - .getChildrenTextLen() - .plus(child.getNodeText().length) - } else if (child.node.elementType == SqlTypes.DOT || - child.node.elementType == SqlTypes.RIGHT_PAREN - ) { - // Since elements do not include surrounding spaces, they should be excluded from the character count. - 0 - } else { - child.getNodeText().length.plus(1) - } + fun getChildrenTextLen(): Int = childBlocks.sumOf { child -> calculateChildTextLength(child) } + + private fun calculateChildTextLength(child: SqlBlock): Int { + val nonCommentChildren = child.childBlocks.filterNot { it is SqlDefaultCommentBlock } + + if (nonCommentChildren.isNotEmpty()) { + return child.getChildrenTextLen() + child.getNodeText().length } + if (isExcludedFromTextLength(child)) { + return 0 + } + return child.getNodeText().length + 1 + } + + private fun isExcludedFromTextLength(block: SqlBlock): Boolean = block.node.elementType in setOf(SqlTypes.DOT, SqlTypes.RIGHT_PAREN) fun getChildBlocksDropLast( dropIndex: Int = 1, @@ -122,34 +120,48 @@ open class SqlBlock( fun isEnableFormat(): Boolean = enableFormat - open fun isSaveSpace(lastGroup: SqlBlock?): Boolean { + open fun isSaveSpace(lastGroup: SqlBlock?): Boolean = parentBlock?.let { parent -> - if (parent is SqlElConditionLoopCommentBlock) { - val prevBlock = - prevBlocks.lastOrNull { it !is SqlDefaultCommentBlock } - return prevBlock is SqlElConditionLoopCommentBlock && - (prevBlock.conditionType.isElse() || prevBlock.conditionType.isEnd()) || - parent.childBlocks.dropLast(1).isEmpty() - } - // Checks for non-breaking keyword combinations, ignoring comment blocks - if (parent is SqlNewGroupBlock) { - val prevWord = prevBlocks.lastOrNull { it !is SqlCommentBlock } - if (SqlKeywordUtil.isSetLineKeyword(getNodeText(), parent.getNodeText()) || - SqlKeywordUtil.isSetLineKeyword(getNodeText(), prevWord?.getNodeText() ?: "") - ) { - return false - } - // Breaks a line if it is a child of itself or preceded by a condition/loop directive - return childBlocks.lastOrNull() is SqlElConditionLoopCommentBlock || - ( - prevBlocks.lastOrNull() is SqlElConditionLoopCommentBlock && - prevBlocks - .last() - .node.psi.startOffset > parent.node.psi.startOffset - ) + when (parent) { + is SqlElConditionLoopCommentBlock -> shouldSaveSpaceForConditionLoop(parent) + is SqlNewGroupBlock -> shouldSaveSpaceForNewGroup(parent) + else -> false } + } == true + + private fun shouldSaveSpaceForConditionLoop(parent: SqlElConditionLoopCommentBlock): Boolean { + val prevBlock = prevBlocks.lastOrNull { it !is SqlDefaultCommentBlock } + val isPrevBlockElseOrEnd = + prevBlock is SqlElConditionLoopCommentBlock && + (prevBlock.conditionType.isElse() || prevBlock.conditionType.isEnd()) + val hasNoChildrenExceptLast = parent.childBlocks.dropLast(1).isEmpty() + + return isPrevBlockElseOrEnd || hasNoChildrenExceptLast + } + + private fun shouldSaveSpaceForNewGroup(parent: SqlNewGroupBlock): Boolean { + val prevWord = prevBlocks.lastOrNull { it !is SqlCommentBlock } + + if (isNonBreakingKeywordCombination(parent, prevWord)) { + return false } - return false + + return isFollowedByConditionLoop() || isPrecededByConditionLoop(parent) + } + + private fun isNonBreakingKeywordCombination( + parent: SqlNewGroupBlock, + prevWord: SqlBlock?, + ): Boolean = + SqlKeywordUtil.isSetLineKeyword(getNodeText(), parent.getNodeText()) || + SqlKeywordUtil.isSetLineKeyword(getNodeText(), prevWord?.getNodeText() ?: "") + + private fun isFollowedByConditionLoop(): Boolean = childBlocks.lastOrNull() is SqlElConditionLoopCommentBlock + + private fun isPrecededByConditionLoop(parent: SqlNewGroupBlock): Boolean { + val lastPrevBlock = prevBlocks.lastOrNull() + return lastPrevBlock is SqlElConditionLoopCommentBlock && + lastPrevBlock.node.psi.startOffset > parent.node.psi.startOffset } /** @@ -193,11 +205,15 @@ open class SqlBlock( */ override fun getChildIndent(): Indent? = if (isEnableFormat()) { - Indent.getSpaceIndent(4) + Indent.getSpaceIndent(DEFAULT_INDENT_SIZE) } else { Indent.getSpaceIndent(0) } + companion object { + private const val DEFAULT_INDENT_SIZE = 4 + } + /** * Determines whether the block is a leaf node. */ diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt index 577f99c5..300956b0 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt @@ -61,7 +61,7 @@ import org.domaframework.doma.intellij.formatter.processor.SqlSetParentGroupProc import org.domaframework.doma.intellij.formatter.util.CreateTableUtil import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext -import org.domaframework.doma.intellij.formatter.util.SqlBlockUtil +import org.domaframework.doma.intellij.formatter.util.SqlBlockGenerator import org.domaframework.doma.intellij.psi.SqlTypes class SqlFileBlock( @@ -95,7 +95,7 @@ class SqlFileBlock( private val blockBuilder = SqlBlockBuilder() private val parentSetProcessor = SqlSetParentGroupProcessor(blockBuilder) - private val blockUtil = SqlBlockUtil(this, isEnableFormat(), formatMode) + private val blockUtil = SqlBlockGenerator(this, isEnableFormat(), formatMode) private val pendingCommentBlocks = mutableListOf() @@ -114,9 +114,6 @@ class SqlFileBlock( updateCommentParentAndIdent(childBlock) updateBlockParentAndLAddGroup(childBlock) updateWhiteSpaceInclude(lastBlock, childBlock, lastGroup) - // TODO After processing the END directive block, - // if there is only one element (with two or fewer spaces), - // remove the line breaks within the if~end block and consolidate it into a single line. blocks.add(childBlock) } else { if (lastBlock !is SqlLineCommentBlock) { diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt index 7084ecbb..be4b73fe 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt @@ -270,6 +270,11 @@ class SqlElConditionLoopCommentBlock( override fun createGroupIndentLen(): Int = indent.indentLen + /** + * Count the number of [SqlElConditionLoopCommentBlock] within the same parent block. + * Since the current directive is included in the count, + * **subtract 1 at the end** to exclude itself. + */ private fun getOpenDirectiveCount(parent: SqlBlock): Int { val conditionLoopDirectives: List = parent diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlPostProcessor.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlPostProcessor.kt index 69eef4c7..2f2a2dfe 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlPostProcessor.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlPostProcessor.kt @@ -27,6 +27,12 @@ import com.intellij.psi.impl.source.codeStyle.PostFormatProcessor import org.domaframework.doma.intellij.setting.SqlLanguage class SqlPostProcessor : PostFormatProcessor { + companion object { + private const val FILE_END_PADDING = " \n" + } + + private val trailingSpacesRegex = Regex(" +(\r?\n)") + override fun processElement( source: PsiElement, settings: CodeStyleSettings, @@ -37,25 +43,44 @@ class SqlPostProcessor : PostFormatProcessor { rangeToReformat: TextRange, settings: CodeStyleSettings, ): TextRange { - if (source.language != SqlLanguage.INSTANCE) return rangeToReformat - - val project: Project = source.project - val document = PsiDocumentManager.getInstance(project).getDocument(source) ?: return rangeToReformat + if (!isSqlFile(source)) { + return rangeToReformat + } - val originalText = document.text - val withoutTrailingSpaces = originalText.replace(Regex(" +(\r?\n)"), "$1") - val finalText = withoutTrailingSpaces.trimEnd() + " \n" + val document = getDocument(source) ?: return rangeToReformat + val processedText = processDocumentText(document.text) - if (originalText == finalText) { + if (document.text == processedText) { return rangeToReformat } + updateDocument(source.project, document, processedText) + return TextRange(0, processedText.length) + } + + private fun isSqlFile(source: PsiFile): Boolean = source.language == SqlLanguage.INSTANCE + + private fun getDocument(source: PsiFile) = PsiDocumentManager.getInstance(source.project).getDocument(source) + + private fun processDocumentText(originalText: String): String { + val withoutTrailingSpaces = removeTrailingSpaces(originalText) + return ensureProperFileEnding(withoutTrailingSpaces) + } + + private fun removeTrailingSpaces(text: String): String = text.replace(trailingSpacesRegex, "$1") + + private fun ensureProperFileEnding(text: String): String = text.trimEnd() + FILE_END_PADDING + + private fun updateDocument( + project: Project, + document: com.intellij.openapi.editor.Document, + newText: String, + ) { ApplicationManager.getApplication().invokeAndWait { WriteCommandAction.runWriteCommandAction(project) { - document.setText(finalText) + document.setText(newText) PsiDocumentManager.getInstance(project).commitDocument(document) } } - return TextRange(0, finalText.length) } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt index 7f637bf5..a7bd8443 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt @@ -51,15 +51,28 @@ class SqlSetParentGroupProcessor( val blockBuilder: SqlBlockBuilder, ) - private val newGroupExpectedTypes = - listOf( - SqlSubGroupBlock::class, - SqlCreateViewGroupBlock::class, - SqlInlineGroupBlock::class, - SqlInlineSecondGroupBlock::class, - SqlColumnDefinitionRawGroupBlock::class, - SqlLateralGroupBlock::class, - ) + companion object { + private val NEW_GROUP_EXPECTED_TYPES = + listOf( + SqlSubGroupBlock::class, + SqlCreateViewGroupBlock::class, + SqlInlineGroupBlock::class, + SqlInlineSecondGroupBlock::class, + SqlColumnDefinitionRawGroupBlock::class, + SqlLateralGroupBlock::class, + ) + + private val TOP_LEVEL_EXPECTED_TYPES = + listOf( + SqlSubGroupBlock::class, + SqlCreateViewGroupBlock::class, + ) + + private val COLUMN_RAW_EXPECTED_TYPES = + listOf( + SqlColumnRawGroupBlock::class, + ) + } /** * Sets the parent of the latest group block and registers itself as a child element. @@ -118,125 +131,135 @@ class SqlSetParentGroupProcessor( lastIndentLevel: IndentType, childBlock: SqlKeywordGroupBlock, ) { - val context = - SetParentContext( - childBlock, - blockBuilder, - ) - + val context = SetParentContext(childBlock, blockBuilder) if (lastGroupBlock is SqlElConditionLoopCommentBlock) { - updateParentGroupLastConditionLoop(lastGroupBlock, context) { - it.indent.indentLevel < childBlock.indent.indentLevel - } - return + handleConditionLoopParent(lastGroupBlock, context, childBlock) + } else if (childBlock.indent.indentLevel == IndentType.TOP) { + handleTopLevelKeyword(lastGroupBlock, childBlock, context) + } else { + handleNonTopLevelKeyword(lastGroupBlock, lastIndentLevel, childBlock, context) } + } - val currentIndentLevel = childBlock.indent.indentLevel - if (currentIndentLevel == IndentType.TOP) { - var parentBlock: SqlBlock? = null - val expectedTypes = - listOf( - SqlSubGroupBlock::class, - SqlCreateViewGroupBlock::class, - ) - if (isExpectedClassType(expectedTypes, lastGroupBlock)) { - parentBlock = lastGroupBlock + private fun handleConditionLoopParent( + lastGroupBlock: SqlElConditionLoopCommentBlock, + context: SetParentContext, + childBlock: SqlKeywordGroupBlock, + ) { + updateParentGroupLastConditionLoop(lastGroupBlock, context) { + it.indent.indentLevel < childBlock.indent.indentLevel + } + } + + private fun handleTopLevelKeyword( + lastGroupBlock: SqlBlock, + childBlock: SqlKeywordGroupBlock, + context: SetParentContext, + ) { + val parentBlock = + if (isExpectedClassType(TOP_LEVEL_EXPECTED_TYPES, lastGroupBlock)) { + lastGroupBlock + } else if (childBlock is SqlUpdateQueryGroupBlock) { + UpdateClauseUtil.getParentGroupBlock(blockBuilder, childBlock) } else { - when (childBlock) { - is SqlUpdateQueryGroupBlock -> { - UpdateClauseUtil - .getParentGroupBlock(blockBuilder, childBlock) - ?.let { parentBlock = it } - } + findTopLevelParent() + } + setParentGroups(context) { return@setParentGroups parentBlock } + } - else -> { - val topKeywordIndex = - blockBuilder.getGroupTopNodeIndex { block -> - block.indent.indentLevel == IndentType.TOP - } - val subGroupIndex = - blockBuilder.getGroupTopNodeIndex { block -> - block is SqlSubGroupBlock - } - - var deleteIndex = topKeywordIndex - if (topKeywordIndex >= 0 && subGroupIndex < 0) { - val copyParentBlock = - blockBuilder.getGroupTopNodeIndexHistory()[topKeywordIndex] - parentBlock = copyParentBlock.parentBlock - } else if (topKeywordIndex > subGroupIndex) { - val copyParentBlock = - blockBuilder.getGroupTopNodeIndexHistory()[subGroupIndex] - parentBlock = copyParentBlock - } - if (deleteIndex >= 0) { - blockBuilder.clearSubListGroupTopNodeIndexHistory(deleteIndex) - } - } - } + private fun findTopLevelParent(): SqlBlock? { + val topKeywordIndex = + blockBuilder.getGroupTopNodeIndex { + it.indent.indentLevel == IndentType.TOP } - setParentGroups(context) { history -> - return@setParentGroups parentBlock + val subGroupIndex = + blockBuilder.getGroupTopNodeIndex { + it is SqlSubGroupBlock } - return - } - if (lastGroupBlock.indent.indentLevel == IndentType.SUB) { - setParentGroups(context) { history -> - return@setParentGroups lastGroupBlock - } - } else if (lastIndentLevel == currentIndentLevel) { - val prevKeyword = lastGroupBlock.childBlocks.findLast { it is SqlKeywordBlock } - prevKeyword?.let { prev -> - if (SqlKeywordUtil.isSetLineKeyword(childBlock.getNodeText(), prev.getNodeText())) { - updateGroupBlockLastGroupParentAddGroup( - lastGroupBlock, - childBlock, - ) - return + val (parentBlock, deleteIndex) = + when { + topKeywordIndex >= 0 && subGroupIndex < 0 -> { + val block = blockBuilder.getGroupTopNodeIndexHistory()[topKeywordIndex] + block.parentBlock to topKeywordIndex } + topKeywordIndex > subGroupIndex -> { + val block = blockBuilder.getGroupTopNodeIndexHistory()[subGroupIndex] + block to topKeywordIndex + } + else -> null to -1 } - blockBuilder.removeLastGroupTopNodeIndexHistory() - if (childBlock is SqlReturningGroupBlock) { - // Since `DO UPDATE` does not include a `RETURNING` clause, it should be registered as a child of the parent `INSERT` query. - // The `DO` keyword should align with the `INSERT` query, and therefore it will serve as the **indentation anchor** for the following update block. + if (deleteIndex >= 0) { + blockBuilder.clearSubListGroupTopNodeIndexHistory(deleteIndex) + } + + return parentBlock + } + + private fun handleNonTopLevelKeyword( + lastGroupBlock: SqlBlock, + lastIndentLevel: IndentType, + childBlock: SqlKeywordGroupBlock, + context: SetParentContext, + ) { + when { + lastGroupBlock.indent.indentLevel == IndentType.SUB -> { + setParentGroups(context) { lastGroupBlock } + } + lastIndentLevel == childBlock.indent.indentLevel -> { + handleSameLevelKeyword(lastGroupBlock, childBlock, context) + } + lastIndentLevel < childBlock.indent.indentLevel -> { + updateGroupBlockParentAndAddGroup(childBlock) + } + shouldHandleJoinKeyword(lastIndentLevel, childBlock) -> { + updateGroupBlockParentAndAddGroup(childBlock) + } + else -> { setParentGroups(context) { history -> - val lastGroup = history.findLast { it is SqlTopQueryGroupBlock } - return@setParentGroups if (lastGroup is SqlUpdateQueryGroupBlock && lastGroup.parentBlock is SqlDoGroupBlock) { - lastGroup.parentBlock - } else { - lastGroup - } + history.lastOrNull { it.indent.indentLevel < childBlock.indent.indentLevel } } - return } - updateGroupBlockLastGroupParentAddGroup( - lastGroupBlock, - childBlock, - ) - } else if (lastIndentLevel < currentIndentLevel) { - updateGroupBlockParentAndAddGroup( - childBlock, - ) - } else if (lastIndentLevel == IndentType.JOIN && - SqlKeywordUtil.isSecondOptionKeyword(childBlock.getNodeText()) - ) { - // left,right < inner,outer < join - updateGroupBlockParentAndAddGroup( - childBlock, - ) + } + } + + private fun handleSameLevelKeyword( + lastGroupBlock: SqlBlock, + childBlock: SqlKeywordGroupBlock, + context: SetParentContext, + ) { + val prevKeyword = lastGroupBlock.childBlocks.findLast { it is SqlKeywordBlock } + if (prevKeyword != null && SqlKeywordUtil.isSetLineKeyword(childBlock.getNodeText(), prevKeyword.getNodeText())) { + updateGroupBlockLastGroupParentAddGroup(lastGroupBlock, childBlock) return + } + + blockBuilder.removeLastGroupTopNodeIndexHistory() + + if (childBlock is SqlReturningGroupBlock) { + handleReturningBlock(context) } else { - setParentGroups(context) { history -> - return@setParentGroups history - .lastOrNull { - it.indent.indentLevel < childBlock.indent.indentLevel - } + updateGroupBlockLastGroupParentAddGroup(lastGroupBlock, childBlock) + } + } + + private fun handleReturningBlock(context: SetParentContext) { + setParentGroups(context) { history -> + val lastGroup = history.findLast { it is SqlTopQueryGroupBlock } + when { + lastGroup is SqlUpdateQueryGroupBlock && lastGroup.parentBlock is SqlDoGroupBlock -> + lastGroup.parentBlock + else -> lastGroup } } } + private fun shouldHandleJoinKeyword( + lastIndentLevel: IndentType, + childBlock: SqlKeywordGroupBlock, + ): Boolean = lastIndentLevel == IndentType.JOIN && SqlKeywordUtil.isSecondOptionKeyword(childBlock.getNodeText()) + fun updateColumnDefinitionRawGroupBlockParentAndAddGroup( lastGroupBlock: SqlBlock, lastIndentLevel: IndentType, @@ -261,10 +284,6 @@ class SqlSetParentGroupProcessor( lastGroupBlock: SqlBlock, childBlock: SqlColumnRawGroupBlock, ) { - val expectedTypes = - listOf( - SqlColumnRawGroupBlock::class, - ) val context = SetParentContext( childBlock, @@ -278,7 +297,7 @@ class SqlSetParentGroupProcessor( return } - if (isExpectedClassType(expectedTypes, lastGroupBlock)) { + if (isExpectedClassType(COLUMN_RAW_EXPECTED_TYPES, lastGroupBlock)) { blockBuilder.removeLastGroupTopNodeIndexHistory() } setParentGroups(context) { history -> @@ -337,35 +356,34 @@ class SqlSetParentGroupProcessor( context: SetParentContext, findDefaultParent: (SqlBlock) -> Boolean, ) { - val childBlock = context.childBlock if (lastGroupBlock.parentBlock != null) { - setParentGroups(context) { history -> - return@setParentGroups lastGroupBlock - } - } else { - val history = blockBuilder.getGroupTopNodeIndexHistory() - val findParent = - history - .lastOrNull { block -> - findDefaultParent(block) || - (block is SqlElConditionLoopCommentBlock && block.parentBlock != null) - } - // Search for keyword groups with a level lower than or equal to the current level, - // or conditional directives that already have a parent assigned. - if (findParent is SqlElConditionLoopCommentBlock) { - // Set the parent of the most recent conditional directive to the current node. + setParentGroups(context) { lastGroupBlock } + return + } + + val findParent = findParentForConditionLoop(findDefaultParent) + handleConditionLoopParentAssignment(lastGroupBlock, context, findParent) + } + + private fun findParentForConditionLoop(findDefaultParent: (SqlBlock) -> Boolean): SqlBlock? = + blockBuilder.getGroupTopNodeIndexHistory().lastOrNull { block -> + findDefaultParent(block) || + (block is SqlElConditionLoopCommentBlock && block.parentBlock != null) + } + + private fun handleConditionLoopParentAssignment( + lastGroupBlock: SqlElConditionLoopCommentBlock, + context: SetParentContext, + findParent: SqlBlock?, + ) { + when (findParent) { + is SqlElConditionLoopCommentBlock -> { lastGroupBlock.setParentGroupBlock(findParent) - setParentGroups(context) { history -> - return@setParentGroups lastGroupBlock - } + setParentGroups(context) { lastGroupBlock } } - if (findParent !is SqlElConditionLoopCommentBlock) { - // If a keyword group with a level lower than or equal to the current level is found, - // set that keyword group as the parent, and set the parent of the most recent conditional directive to the current node. - setParentGroups(context) { history -> - return@setParentGroups findParent - } - lastGroupBlock.setParentGroupBlock(childBlock) + else -> { + setParentGroups(context) { findParent } + lastGroupBlock.setParentGroupBlock(context.childBlock) } } } @@ -485,10 +503,7 @@ class SqlSetParentGroupProcessor( } if (isNewGroup(targetChildBlock, context.blockBuilder) || - isExpectedClassType( - newGroupExpectedTypes, - targetChildBlock, - ) + isExpectedClassType(NEW_GROUP_EXPECTED_TYPES, targetChildBlock) ) { context.blockBuilder.addGroupTopNodeIndexHistory(targetChildBlock) } @@ -505,16 +520,18 @@ class SqlSetParentGroupProcessor( childBlock: SqlBlock, blockBuilder: SqlBlockBuilder, ): Boolean { - if (childBlock is SqlElConditionLoopCommentBlock) { - if (childBlock.conditionType.isStartDirective() || childBlock.conditionType.isElse()) { - return true - } + if (isConditionLoopNewGroup(childBlock)) { + return true } val lastGroup = blockBuilder.getLastGroupTopNodeIndexHistory() return isNewGroupAndNotSetLineKeywords(childBlock, lastGroup) } + private fun isConditionLoopNewGroup(childBlock: SqlBlock): Boolean = + childBlock is SqlElConditionLoopCommentBlock && + (childBlock.conditionType.isStartDirective() || childBlock.conditionType.isElse()) + fun isNewGroupAndNotSetLineKeywords( childBlock: SqlBlock, lastGroup: SqlBlock?, @@ -539,9 +556,14 @@ class SqlSetParentGroupProcessor( * 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. */ - fun getLastGroupKeywordText(lastGroup: SqlBlock?): String = - lastGroup - ?.childBlocks - ?.lastOrNull { it.node.elementType == SqlTypes.KEYWORD } - ?.getNodeText() ?: lastGroup?.getNodeText() ?: "" + private fun getLastGroupKeywordText(lastGroup: SqlBlock?): String { + if (lastGroup == null) return "" + + val keywordBlock = + lastGroup.childBlocks.lastOrNull { + it.node.elementType == SqlTypes.KEYWORD + } + + return keywordBlock?.getNodeText() ?: lastGroup.getNodeText() + } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CommaRawUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CommaRawUtil.kt index 41eebcad..7515a2be 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CommaRawUtil.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CommaRawUtil.kt @@ -24,37 +24,67 @@ import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordG import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithCommonTableGroupBlock object CommaRawUtil { + /** + * Creates an appropriate comma block based on the last group context. + * Handles special cases for condition/loop comment blocks and different group types. + */ fun getCommaBlock( lastGroup: SqlBlock?, child: ASTNode, sqlBlockFormattingCtx: SqlBlockFormattingContext, ): SqlBlock = - if (lastGroup is SqlElConditionLoopCommentBlock) { - if (lastGroup.parentBlock == null) { - getSqlCommaBlock(lastGroup.tempParentBlock, child, sqlBlockFormattingCtx) - } else { - getSqlCommaBlock(lastGroup.parentBlock, child, sqlBlockFormattingCtx) - } - } else { - getSqlCommaBlock(lastGroup, child, sqlBlockFormattingCtx) + when (lastGroup) { + is SqlElConditionLoopCommentBlock -> + createCommaBlockForConditionLoop( + lastGroup, + child, + sqlBlockFormattingCtx, + ) + + else -> createCommaBlockForGroup(lastGroup, child, sqlBlockFormattingCtx) } - private fun getSqlCommaBlock( + /** + * Creates a comma block for condition/loop comment blocks. + * Uses the parent block if available, otherwise uses the temporary parent block. + */ + private fun createCommaBlockForConditionLoop( + lastGroup: SqlElConditionLoopCommentBlock, + child: ASTNode, + sqlBlockFormattingCtx: SqlBlockFormattingContext, + ): SqlBlock { + val effectiveParent = lastGroup.parentBlock ?: lastGroup.tempParentBlock + return createCommaBlockForGroup(effectiveParent, child, sqlBlockFormattingCtx) + } + + /** + * Creates an appropriate comma block based on the group type and indent level. + */ + private fun createCommaBlockForGroup( lastGroup: SqlBlock?, child: ASTNode, sqlBlockFormattingCtx: SqlBlockFormattingContext, ): SqlBlock = - when (lastGroup) { - is SqlColumnRawGroupBlock, is SqlKeywordGroupBlock -> { - if (lastGroup.indent.indentLevel == IndentType.SECOND) { - SqlCommaBlock(child, sqlBlockFormattingCtx) - } else { - SqlColumnRawGroupBlock(child, sqlBlockFormattingCtx) - } - } + when { + shouldCreateColumnRawBlock(lastGroup) -> + SqlColumnRawGroupBlock( + child, + sqlBlockFormattingCtx, + ) - is SqlWithCommonTableGroupBlock -> SqlWithCommonTableGroupBlock(child, sqlBlockFormattingCtx) + lastGroup is SqlWithCommonTableGroupBlock -> + SqlWithCommonTableGroupBlock( + child, + sqlBlockFormattingCtx, + ) else -> SqlCommaBlock(child, sqlBlockFormattingCtx) } + + /** + * Determines if a column raw block should be created based on the group type and indent level. + */ + private fun shouldCreateColumnRawBlock(lastGroup: SqlBlock?): Boolean = + (lastGroup is SqlColumnRawGroupBlock || lastGroup is SqlKeywordGroupBlock) && + lastGroup.indent.indentLevel != IndentType.SECOND } diff --git a/src/test/testData/sql/formatter/NestedDirectives.sql b/src/test/testData/sql/formatter/NestedDirectives.sql index 888da92f..81f35456 100644 --- a/src/test/testData/sql/formatter/NestedDirectives.sql +++ b/src/test/testData/sql/formatter/NestedDirectives.sql @@ -1,4 +1,5 @@ -SELECT e.id , e.name , d.name AS department_name +SELECT e.id , e.name , d.name AS department_name /*%if addColumn */ + , d.location AS department_location /*%end */ FROM employee e /*%if includesDepartment */ LEFT JOIN department d ON e.department_id = d.id @@ -29,7 +30,7 @@ ASC /*%end */ -- END5 /*%end */ -- END3 /*%if sort_has_next */ -- IF8 -, + e.sort_field , /*%end */ -- END8 /*%end */ -- END2 /*%else */ -- ELSE1 diff --git a/src/test/testData/sql/formatter/NestedDirectives_format.sql b/src/test/testData/sql/formatter/NestedDirectives_format.sql index 609db932..4ff0c40a 100644 --- a/src/test/testData/sql/formatter/NestedDirectives_format.sql +++ b/src/test/testData/sql/formatter/NestedDirectives_format.sql @@ -1,6 +1,9 @@ SELECT e.id , e.name , d.name AS department_name + /*%if addColumn */ + , d.location AS department_location + /*%end */ FROM employee e /*%if includesDepartment */ LEFT JOIN department d @@ -39,6 +42,7 @@ SELECT e.id /*%end */ -- END5 /*%end */ -- END3 /*%if sort_has_next */ -- IF8 + e.sort_field , /*%end */ -- END8 /*%end */ -- END2 From 3821fe7f61930b4e9e7b028309cf54b497e7a4b1 Mon Sep 17 00:00:00 2001 From: xterao Date: Fri, 18 Jul 2025 20:02:37 +0900 Subject: [PATCH 11/11] Refactor SQL formatting utilities to improve structure and rename for clarity --- .../intellij/formatter/block/SqlFileBlock.kt | 4 +- .../CommaRawClauseHandler.kt} | 6 +- .../CreateClauseHandler.kt} | 5 +- .../InsertClauseHandler.kt} | 5 +- .../JoinClauseHandler.kt} | 9 +- .../formatter/handler/NotQueryGroupHandler.kt | 120 ++++++++++++++++++ .../UpdateClauseHandler.kt} | 6 +- .../WithClauseHandler.kt} | 9 +- .../processor/SqlSetParentGroupProcessor.kt | 4 +- .../formatter/util/NotQueryGroupUtil.kt | 86 ------------- .../{SqlBlockUtil.kt => SqlBlockGenerator.kt} | 35 +++-- 11 files changed, 171 insertions(+), 118 deletions(-) rename src/main/kotlin/org/domaframework/doma/intellij/formatter/{util/CommaRawUtil.kt => handler/CommaRawClauseHandler.kt} (93%) rename src/main/kotlin/org/domaframework/doma/intellij/formatter/{util/CreateTableUtil.kt => handler/CreateClauseHandler.kt} (96%) rename src/main/kotlin/org/domaframework/doma/intellij/formatter/{util/InsertClauseUtil.kt => handler/InsertClauseHandler.kt} (91%) rename src/main/kotlin/org/domaframework/doma/intellij/formatter/{util/JoinGroupUtil.kt => handler/JoinClauseHandler.kt} (81%) create mode 100644 src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/NotQueryGroupHandler.kt rename src/main/kotlin/org/domaframework/doma/intellij/formatter/{util/UpdateClauseUtil.kt => handler/UpdateClauseHandler.kt} (92%) rename src/main/kotlin/org/domaframework/doma/intellij/formatter/{util/WithClauseUtil.kt => handler/WithClauseHandler.kt} (88%) delete mode 100644 src/main/kotlin/org/domaframework/doma/intellij/formatter/util/NotQueryGroupUtil.kt rename src/main/kotlin/org/domaframework/doma/intellij/formatter/util/{SqlBlockUtil.kt => SqlBlockGenerator.kt} (94%) diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt index 300956b0..914bec05 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt @@ -57,8 +57,8 @@ import org.domaframework.doma.intellij.formatter.block.word.SqlTableBlock import org.domaframework.doma.intellij.formatter.block.word.SqlWordBlock import org.domaframework.doma.intellij.formatter.builder.SqlBlockBuilder import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder +import org.domaframework.doma.intellij.formatter.handler.CreateClauseHandler import org.domaframework.doma.intellij.formatter.processor.SqlSetParentGroupProcessor -import org.domaframework.doma.intellij.formatter.util.CreateTableUtil import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext import org.domaframework.doma.intellij.formatter.util.SqlBlockGenerator @@ -552,7 +552,7 @@ class SqlFileBlock( } // Create Table Column Definition Raw Group Block - CreateTableUtil + CreateClauseHandler .getColumnDefinitionRawGroupSpacing(childBlock1, childBlock2) ?.let { return it } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CommaRawUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/CommaRawClauseHandler.kt similarity index 93% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CommaRawUtil.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/CommaRawClauseHandler.kt index 7515a2be..5d4a028c 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CommaRawUtil.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/CommaRawClauseHandler.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.util +package org.domaframework.doma.intellij.formatter.handler import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock @@ -22,8 +22,10 @@ import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoo import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnRawGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithCommonTableGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext -object CommaRawUtil { +object CommaRawClauseHandler { /** * Creates an appropriate comma block based on the last group context. * Handles special cases for condition/loop comment blocks and different group types. diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CreateTableUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/CreateClauseHandler.kt similarity index 96% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CreateTableUtil.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/CreateClauseHandler.kt index 22e2fbac..94ac6d7b 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CreateTableUtil.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/CreateClauseHandler.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.util +package org.domaframework.doma.intellij.formatter.handler import com.intellij.formatting.Block import com.intellij.formatting.Spacing @@ -24,9 +24,10 @@ import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnBlo import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateTableColumnDefinitionGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateTableColumnDefinitionRawGroupBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext import org.domaframework.doma.intellij.psi.SqlTypes -object CreateTableUtil { +object CreateClauseHandler { fun getCreateTableClauseSubGroup( lastGroup: SqlBlock, child: ASTNode, diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/InsertClauseUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/InsertClauseHandler.kt similarity index 91% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/util/InsertClauseUtil.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/InsertClauseHandler.kt index e7b8efda..6cb071c7 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/InsertClauseUtil.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/InsertClauseHandler.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.util +package org.domaframework.doma.intellij.formatter.handler import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock @@ -22,8 +22,9 @@ import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlI import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertValueGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlValuesGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext -object InsertClauseUtil { +object InsertClauseHandler { fun getInsertClauseSubGroup( lastGroup: SqlBlock, child: ASTNode, diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/JoinGroupUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/JoinClauseHandler.kt similarity index 81% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/util/JoinGroupUtil.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/JoinClauseHandler.kt index f4ec5bb6..28aa2dc5 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/JoinGroupUtil.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/JoinClauseHandler.kt @@ -13,21 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.util +package org.domaframework.doma.intellij.formatter.handler import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlJoinGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext +import org.domaframework.doma.intellij.formatter.util.SqlKeywordUtil -object JoinGroupUtil { +object JoinClauseHandler { fun getJoinKeywordGroupBlock( lastGroupBlock: SqlBlock?, keywordText: String, child: ASTNode, sqlBlockFormattingCtx: SqlBlockFormattingContext, ): SqlBlock = - if (SqlKeywordUtil.isJoinKeyword(keywordText)) { + if (SqlKeywordUtil.Companion.isJoinKeyword(keywordText)) { SqlJoinGroupBlock( child, sqlBlockFormattingCtx, diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/NotQueryGroupHandler.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/NotQueryGroupHandler.kt new file mode 100644 index 00000000..77937794 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/NotQueryGroupHandler.kt @@ -0,0 +1,120 @@ +/* + * 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.handler + +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.SqlCommaBlock +import org.domaframework.doma.intellij.formatter.block.conflict.SqlConflictClauseBlock +import org.domaframework.doma.intellij.formatter.block.conflict.SqlConflictExpressionSubGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.condition.SqlConditionKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.condition.SqlConditionalExpressionGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlReturningGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlValuesGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlFunctionParamBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlParallelListBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlValuesParamGroupBlock +import org.domaframework.doma.intellij.formatter.block.word.SqlAliasBlock +import org.domaframework.doma.intellij.formatter.block.word.SqlTableBlock +import org.domaframework.doma.intellij.formatter.block.word.SqlWordBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext +import org.domaframework.doma.intellij.formatter.util.SqlKeywordUtil + +object NotQueryGroupHandler { + private const val IN_KEYWORD = "in" + private const val RETURNING_KEYWORD = "returning" + + /** + * Creates an appropriate [org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock] based on the last group context and node type. + * Returns null if no specific subgroup is needed. + */ + fun getSubGroup( + lastGroup: SqlBlock?, + child: ASTNode, + sqlBlockFormattingCtx: SqlBlockFormattingContext, + ): SqlBlock? = + when { + hasInKeyword(lastGroup) -> SqlParallelListBlock(child, sqlBlockFormattingCtx) + lastGroup is SqlConditionKeywordGroupBlock -> createConditionalExpressionGroup(child, sqlBlockFormattingCtx) + hasFunctionOrAliasContext(lastGroup) -> createFunctionOrValueBlock(lastGroup, child, sqlBlockFormattingCtx) + lastGroup is SqlConflictClauseBlock -> SqlConflictExpressionSubGroupBlock(child, sqlBlockFormattingCtx) + hasValuesContext(lastGroup) -> SqlValuesParamGroupBlock(child, sqlBlockFormattingCtx) + else -> null + } + + /** + * Creates a keyword group block for specific keywords. + * Currently only handles 'returning' keyword. + */ + fun getKeywordGroup( + child: ASTNode, + sqlBlockFormattingCtx: SqlBlockFormattingContext, + ): SqlBlock? { + val keyword = child.text.lowercase() + return when (keyword) { + RETURNING_KEYWORD -> SqlReturningGroupBlock(child, sqlBlockFormattingCtx) + else -> null + } + } + + /** + * Checks if the last group has an 'IN' keyword as its last option keyword. + */ + private fun hasInKeyword(lastGroup: SqlBlock?): Boolean { + val lastKeyword = + lastGroup + ?.childBlocks + ?.lastOrNull { SqlKeywordUtil.isOptionSqlKeyword(it.getNodeText()) } + return lastKeyword?.getNodeText()?.lowercase() == IN_KEYWORD + } + + /** + * Creates a conditional expression group block. + */ + private fun createConditionalExpressionGroup( + child: ASTNode, + sqlBlockFormattingCtx: SqlBlockFormattingContext, + ): SqlConditionalExpressionGroupBlock = SqlConditionalExpressionGroupBlock(child, sqlBlockFormattingCtx) + + /** + * Checks if the last group has a word block context that requires function or alias handling. + */ + private fun hasFunctionOrAliasContext(lastGroup: SqlBlock?): Boolean = lastGroup?.childBlocks?.lastOrNull() is SqlWordBlock + + /** + * Creates either a function parameter block or values parameter block based on the previous child type. + */ + private fun createFunctionOrValueBlock( + lastGroup: SqlBlock?, + child: ASTNode, + sqlBlockFormattingCtx: SqlBlockFormattingContext, + ): SqlBlock { + val prevChild = lastGroup?.childBlocks?.lastOrNull() + return when { + prevChild is SqlAliasBlock || prevChild is SqlTableBlock -> + SqlValuesParamGroupBlock(child, sqlBlockFormattingCtx) + else -> + SqlFunctionParamBlock(child, sqlBlockFormattingCtx) + } + } + + /** + * Checks if the context indicates a values parameter group should be created. + */ + private fun hasValuesContext(lastGroup: SqlBlock?): Boolean = + lastGroup is SqlValuesGroupBlock || + (lastGroup is SqlCommaBlock && lastGroup.parentBlock is SqlValuesGroupBlock) +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/UpdateClauseUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/UpdateClauseHandler.kt similarity index 92% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/util/UpdateClauseUtil.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/UpdateClauseHandler.kt index d1fe4710..86629179 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/UpdateClauseUtil.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/UpdateClauseHandler.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.util +package org.domaframework.doma.intellij.formatter.handler import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock @@ -24,8 +24,10 @@ import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlU import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateValueGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock import org.domaframework.doma.intellij.formatter.builder.SqlBlockBuilder +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext -object UpdateClauseUtil { +object UpdateClauseHandler { fun getUpdateClauseSubGroup( lastGroup: SqlBlock, child: ASTNode, diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/WithClauseUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/WithClauseHandler.kt similarity index 88% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/util/WithClauseUtil.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/WithClauseHandler.kt index b0f4044a..4733ddd3 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/WithClauseUtil.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/WithClauseHandler.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.util +package org.domaframework.doma.intellij.formatter.handler import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock @@ -23,9 +23,12 @@ import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWit import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithOptionGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithQuerySubGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext +import org.domaframework.doma.intellij.formatter.util.SqlKeywordUtil import org.domaframework.doma.intellij.psi.SqlTypes -object WithClauseUtil { +object WithClauseHandler { fun getWithClauseSubGroup( lastGroup: SqlBlock, child: ASTNode, @@ -54,7 +57,7 @@ object WithClauseUtil { child: ASTNode, sqlBlockFormattingCtx: SqlBlockFormattingContext, ): SqlBlock? { - if (SqlKeywordUtil.isWithOptionKeyword(child.text)) { + if (SqlKeywordUtil.Companion.isWithOptionKeyword(child.text)) { return SqlWithOptionGroupBlock(child, sqlBlockFormattingCtx) } if (lastGroup is SqlWithOptionGroupBlock) { diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt index a7bd8443..6e439de2 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt @@ -37,9 +37,9 @@ import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWit import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock import org.domaframework.doma.intellij.formatter.block.word.SqlFunctionGroupBlock import org.domaframework.doma.intellij.formatter.builder.SqlBlockBuilder +import org.domaframework.doma.intellij.formatter.handler.UpdateClauseHandler import org.domaframework.doma.intellij.formatter.util.IndentType import org.domaframework.doma.intellij.formatter.util.SqlKeywordUtil -import org.domaframework.doma.intellij.formatter.util.UpdateClauseUtil import org.domaframework.doma.intellij.psi.SqlTypes import kotlin.collections.lastOrNull @@ -160,7 +160,7 @@ class SqlSetParentGroupProcessor( if (isExpectedClassType(TOP_LEVEL_EXPECTED_TYPES, lastGroupBlock)) { lastGroupBlock } else if (childBlock is SqlUpdateQueryGroupBlock) { - UpdateClauseUtil.getParentGroupBlock(blockBuilder, childBlock) + UpdateClauseHandler.getParentGroupBlock(blockBuilder, childBlock) } else { findTopLevelParent() } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/NotQueryGroupUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/NotQueryGroupUtil.kt deleted file mode 100644 index bba6f62e..00000000 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/NotQueryGroupUtil.kt +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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.util - -import com.intellij.lang.ASTNode -import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.SqlCommaBlock -import org.domaframework.doma.intellij.formatter.block.conflict.SqlConflictClauseBlock -import org.domaframework.doma.intellij.formatter.block.conflict.SqlConflictExpressionSubGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.condition.SqlConditionKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.condition.SqlConditionalExpressionGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlReturningGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlValuesGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlFunctionParamBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlParallelListBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlValuesParamGroupBlock -import org.domaframework.doma.intellij.formatter.block.word.SqlAliasBlock -import org.domaframework.doma.intellij.formatter.block.word.SqlTableBlock -import org.domaframework.doma.intellij.formatter.block.word.SqlWordBlock - -object NotQueryGroupUtil { - fun getSubGroup( - lastGroup: SqlBlock?, - child: ASTNode, - sqlBlockFormattingCtx: SqlBlockFormattingContext, - ): SqlBlock? { - val lastKeyword = - lastGroup - ?.childBlocks - ?.lastOrNull { SqlKeywordUtil.isOptionSqlKeyword(it.getNodeText()) } - if (lastKeyword != null && lastKeyword.getNodeText().lowercase() == "in") { - return SqlParallelListBlock(child, sqlBlockFormattingCtx) - } - - if (lastGroup is SqlConditionKeywordGroupBlock) { - return SqlConditionalExpressionGroupBlock( - child, - sqlBlockFormattingCtx, - ) - } - - val prevChild = lastGroup?.childBlocks?.lastOrNull() - if (prevChild is SqlWordBlock) { - if (prevChild is SqlAliasBlock || prevChild is SqlTableBlock) { - return SqlValuesParamGroupBlock(child, sqlBlockFormattingCtx) - } - return SqlFunctionParamBlock(child, sqlBlockFormattingCtx) - } - - if (lastGroup is SqlConflictClauseBlock) { - return SqlConflictExpressionSubGroupBlock(child, sqlBlockFormattingCtx) - } - - if (lastGroup is SqlValuesGroupBlock || - (lastGroup is SqlCommaBlock && lastGroup.parentBlock is SqlValuesGroupBlock) - ) { - return SqlValuesParamGroupBlock(child, sqlBlockFormattingCtx) - } - - return null - } - - fun getKeywordGroup( - child: ASTNode, - sqlBlockFormattingCtx: SqlBlockFormattingContext, - ): SqlBlock? { - val keyword = child.text.lowercase() - if (keyword == "returning") { - return SqlReturningGroupBlock(child, sqlBlockFormattingCtx) - } - return null - } -} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockGenerator.kt similarity index 94% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockUtil.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockGenerator.kt index 5179fed7..96b6277d 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockUtil.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockGenerator.kt @@ -64,6 +64,13 @@ import org.domaframework.doma.intellij.formatter.block.word.SqlFunctionGroupBloc import org.domaframework.doma.intellij.formatter.block.word.SqlTableBlock import org.domaframework.doma.intellij.formatter.block.word.SqlWordBlock import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder +import org.domaframework.doma.intellij.formatter.handler.CommaRawClauseHandler +import org.domaframework.doma.intellij.formatter.handler.CreateClauseHandler +import org.domaframework.doma.intellij.formatter.handler.InsertClauseHandler +import org.domaframework.doma.intellij.formatter.handler.JoinClauseHandler +import org.domaframework.doma.intellij.formatter.handler.NotQueryGroupHandler +import org.domaframework.doma.intellij.formatter.handler.UpdateClauseHandler +import org.domaframework.doma.intellij.formatter.handler.WithClauseHandler import org.domaframework.doma.intellij.psi.SqlCustomElCommentExpr data class SqlBlockFormattingContext( @@ -74,7 +81,7 @@ data class SqlBlockFormattingContext( val formatMode: FormattingMode, ) -class SqlBlockUtil( +class SqlBlockGenerator( sqlBlock: SqlBlock, enableFormat: Boolean, formatMode: FormattingMode, @@ -155,7 +162,7 @@ class SqlBlockUtil( ): SqlBlock { when (indentLevel) { IndentType.JOIN -> { - return JoinGroupUtil.getJoinKeywordGroupBlock( + return JoinClauseHandler.getJoinKeywordGroupBlock( lastGroupBlock, keywordText, child, @@ -237,7 +244,7 @@ class SqlBlockUtil( sqlBlockFormattingCtx, ) } else { - WithClauseUtil + WithClauseHandler .getWithClauseKeywordGroup( lastGroupBlock, child, @@ -263,11 +270,11 @@ class SqlBlockUtil( ) else -> { - WithClauseUtil + WithClauseHandler .getWithClauseKeywordGroup(lastGroupBlock, child, sqlBlockFormattingCtx) ?.let { return it } - NotQueryGroupUtil + NotQueryGroupHandler .getKeywordGroup( child, sqlBlockFormattingCtx, @@ -337,19 +344,19 @@ class SqlBlockUtil( ): SqlBlock { when (lastGroup) { is SqlKeywordGroupBlock -> { - CreateTableUtil + CreateClauseHandler .getCreateTableClauseSubGroup(lastGroup, child, sqlBlockFormattingCtx) ?.let { return it } - WithClauseUtil + WithClauseHandler .getWithClauseSubGroup(lastGroup, child, sqlBlockFormattingCtx) ?.let { return it } - InsertClauseUtil + InsertClauseHandler .getInsertClauseSubGroup(lastGroup, child, sqlBlockFormattingCtx) ?.let { return it } - UpdateClauseUtil + UpdateClauseHandler .getUpdateClauseSubGroup( lastGroup, child, @@ -357,7 +364,7 @@ class SqlBlockUtil( )?.let { return it } // List-type test data for IN clause - NotQueryGroupUtil + NotQueryGroupHandler .getSubGroup(lastGroup, child, sqlBlockFormattingCtx) ?.let { return it } @@ -369,12 +376,12 @@ class SqlBlockUtil( else -> { if (lastGroup is SqlSubGroupBlock) { - WithClauseUtil + WithClauseHandler .getWithClauseSubGroup(lastGroup, child, sqlBlockFormattingCtx) ?.let { return it } } - NotQueryGroupUtil + NotQueryGroupHandler .getSubGroup(lastGroup, child, sqlBlockFormattingCtx) ?.let { return it } @@ -387,11 +394,11 @@ class SqlBlockUtil( lastGroup: SqlBlock?, child: ASTNode, ): SqlBlock { - CreateTableUtil + CreateClauseHandler .getColumnRawGroup(lastGroup, child, sqlBlockFormattingCtx) ?.let { return it } - return CommaRawUtil.getCommaBlock(lastGroup, child, sqlBlockFormattingCtx) + return CommaRawClauseHandler.getCommaBlock(lastGroup, child, sqlBlockFormattingCtx) } fun getWordBlock(