diff --git a/src/main/kotlin/org/domaframework/doma/intellij/common/util/TypeUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/common/util/TypeUtil.kt index b418f280..2ee422c0 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/common/util/TypeUtil.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/common/util/TypeUtil.kt @@ -24,6 +24,8 @@ import org.domaframework.doma.intellij.extension.getJavaClazz import org.domaframework.doma.intellij.extension.psi.getClassAnnotation import org.domaframework.doma.intellij.extension.psi.isDomain import org.domaframework.doma.intellij.extension.psi.isEntity +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import kotlin.reflect.KClass object TypeUtil { /** @@ -94,4 +96,15 @@ object TypeUtil { if (type == null) return false return PsiTypeChecker.isBaseClassType(type) || DomaClassName.isOptionalWrapperType(type.canonicalText) } + + /** + * Determines whether the specified class instance matches. + */ + fun isExpectedClassType( + expectedClasses: List>, + childBlock: SqlBlock, + ): Boolean = + expectedClasses.any { clazz -> + clazz.isInstance(childBlock) + } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlBlockUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlBlockUtil.kt deleted file mode 100644 index 94980c4b..00000000 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlBlockUtil.kt +++ /dev/null @@ -1,303 +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 - -import com.intellij.formatting.FormattingMode -import com.intellij.lang.ASTNode -import com.intellij.psi.PsiComment -import com.intellij.psi.util.PsiTreeUtil -import org.domaframework.doma.intellij.extension.expr.isConditionOrLoopDirective -import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.SqlBlockCommentBlock -import org.domaframework.doma.intellij.formatter.block.SqlColumnBlock -import org.domaframework.doma.intellij.formatter.block.SqlCommaBlock -import org.domaframework.doma.intellij.formatter.block.SqlCommentBlock -import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock -import org.domaframework.doma.intellij.formatter.block.SqlTableBlock -import org.domaframework.doma.intellij.formatter.block.SqlWordBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElBlockCommentBlock -import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlColumnDefinitionRawGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlCreateKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInlineGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInlineSecondGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInsertKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlJoinGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlUpdateKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnDefinitionGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlDataTypeParamBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlFunctionParamBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlInsertColumnGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlParallelListBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateColumnGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateValueGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlViewGroupBlock -import org.domaframework.doma.intellij.psi.SqlCustomElCommentExpr -import org.domaframework.doma.intellij.psi.SqlTypes - -class SqlBlockUtil( - sqlBlock: SqlBlock, - private val enableFormat: Boolean, - private val formatMode: FormattingMode, -) { - val wrap = sqlBlock.wrap - val alignment = sqlBlock.alignment - val spacingBuilder = sqlBlock.spacingBuilder - - fun getKeywordBlock( - child: ASTNode, - lastGroupBlock: SqlBlock?, - ): SqlBlock { - // Because we haven't yet set the parent-child relationship of the block, - // the parent group references groupTopNodeIndexHistory. - val indentLevel = SqlKeywordUtil.getIndentType(child.text) - val keywordText = child.text.lowercase() - if (indentLevel.isNewLineGroup()) { - when (indentLevel) { - IndentType.JOIN -> { - return if (SqlKeywordUtil.isJoinKeyword(child.text)) { - SqlJoinGroupBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } else if (lastGroupBlock is SqlJoinGroupBlock) { - SqlKeywordBlock(child, IndentType.ATTACHED, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } else { - SqlJoinGroupBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - } - - IndentType.INLINE_SECOND -> { - return SqlInlineSecondGroupBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - - IndentType.TOP -> { - if (keywordText == "create") { - return SqlCreateKeywordGroupBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - if (keywordText == "insert") { - return SqlInsertKeywordGroupBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - - return SqlKeywordGroupBlock(child, indentLevel, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - - IndentType.SECOND -> { - return if (keywordText == "set") { - SqlUpdateKeywordGroupBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } else { - SqlKeywordGroupBlock(child, indentLevel, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - } - - else -> { - return SqlKeywordGroupBlock(child, indentLevel, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - } - } - - when (indentLevel) { - IndentType.INLINE -> { - if (!SqlKeywordUtil.isSetLineKeyword( - child.text, - lastGroupBlock?.getNodeText() ?: "", - ) - ) { - return SqlInlineGroupBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - } - - IndentType.ATTACHED -> { - if (lastGroupBlock is SqlCreateKeywordGroupBlock) { - lastGroupBlock.setCreateQueryType(child.text) - return SqlKeywordBlock(child, indentLevel, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - } - - IndentType.OPTIONS -> { - if (child.text.lowercase() == "as") { - val parentCreateBlock = - lastGroupBlock as? SqlCreateKeywordGroupBlock - ?: lastGroupBlock?.parentBlock as? SqlCreateKeywordGroupBlock - if (parentCreateBlock != null && parentCreateBlock.createType == CreateQueryType.VIEW) { - return SqlViewGroupBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - } - } - - else -> return SqlKeywordBlock(child, indentLevel, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - return SqlKeywordBlock(child, indentLevel, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - - fun getSubGroupBlock( - lastGroup: SqlBlock?, - child: ASTNode, - ): SqlBlock { - if (child.treePrev.elementType == SqlTypes.WORD) { - return SqlFunctionParamBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - - when (lastGroup) { - is SqlKeywordGroupBlock -> { - val lastKeyword = - lastGroup.childBlocks - .lastOrNull { SqlKeywordUtil.isOptionSqlKeyword(it.getNodeText()) } - if (lastKeyword != null && lastKeyword.getNodeText().lowercase() == "in") { - return SqlParallelListBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - if (lastGroup is SqlCreateKeywordGroupBlock) { - return SqlColumnDefinitionGroupBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - if (lastGroup is SqlInsertKeywordGroupBlock) { - return SqlInsertColumnGroupBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - if (lastGroup is SqlUpdateKeywordGroupBlock) { - return if (lastGroup.childBlocks.firstOrNull { it is SqlUpdateColumnGroupBlock } == null) { - SqlUpdateColumnGroupBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } else if (lastGroup.childBlocks.lastOrNull { it is SqlUpdateColumnGroupBlock } != null) { - SqlUpdateValueGroupBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } else { - SqlSubQueryGroupBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - } - return SqlSubQueryGroupBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - - is SqlColumnDefinitionRawGroupBlock -> - return SqlDataTypeParamBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - - else -> - return SqlSubQueryGroupBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - } - - fun getCommaGroupBlock( - lastGroup: SqlBlock?, - child: ASTNode, - ): SqlBlock = - when (lastGroup) { - is SqlColumnDefinitionGroupBlock, is SqlColumnDefinitionRawGroupBlock -> - SqlColumnDefinitionRawGroupBlock( - child, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, - ) - - is SqlColumnGroupBlock, is SqlKeywordGroupBlock -> { - if (lastGroup.indent.indentLevel == IndentType.SECOND) { - SqlCommaBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } else { - SqlColumnGroupBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - } - - else -> SqlCommaBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - - fun getWordBlock( - lastGroup: SqlBlock?, - child: ASTNode, - ): SqlBlock = - when (lastGroup) { - is SqlKeywordGroupBlock -> { - when { - SqlKeywordUtil.isBeforeTableKeyword(lastGroup.getNodeText()) -> - SqlTableBlock( - child, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, - ) - - else -> SqlWordBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - } - - is SqlColumnDefinitionGroupBlock -> { - lastGroup.alignmentColumnName = child.text - SqlColumnDefinitionRawGroupBlock( - child, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, - ) - } - - is SqlColumnDefinitionRawGroupBlock -> { - if (lastGroup.childBlocks.isEmpty()) { - lastGroup.columnName = child.text - SqlColumnBlock( - child, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, - ) - } else { - SqlWordBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - } - - else -> SqlWordBlock(child, wrap, alignment, spacingBuilder, enableFormat, formatMode) - } - - fun getBlockCommentBlock( - child: ASTNode, - blockCommentSpacingBuilder: SqlCustomSpacingBuilder?, - ): SqlCommentBlock { - if (PsiTreeUtil.getChildOfType(child.psi, PsiComment::class.java) != null) { - return SqlBlockCommentBlock( - child, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, - ) - } - if (child.psi is SqlCustomElCommentExpr && - (child.psi as SqlCustomElCommentExpr).isConditionOrLoopDirective() - ) { - return SqlElConditionLoopCommentBlock( - child, - wrap, - alignment, - blockCommentSpacingBuilder, - spacingBuilder, - enableFormat, - formatMode, - ) - } - return SqlElBlockCommentBlock( - child, - wrap, - alignment, - blockCommentSpacingBuilder, - spacingBuilder, - enableFormat, - formatMode, - ) - } -} 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 661f656e..3c3e8eb0 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,28 +26,38 @@ import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType -import org.domaframework.doma.intellij.formatter.SqlBlockBuilder -import org.domaframework.doma.intellij.formatter.SqlBlockUtil -import org.domaframework.doma.intellij.formatter.SqlCustomSpacingBuilder -import org.domaframework.doma.intellij.formatter.SqlKeywordUtil +import com.intellij.psi.util.PsiTreeUtil +import org.domaframework.doma.intellij.common.util.TypeUtil.isExpectedClassType +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.expr.SqlElSymbolBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlColumnDefinitionRawGroupBlock import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnBlock +import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnDefinitionRawGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.column.SqlDataTypeBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInlineGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInlineSecondGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnDefinitionGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateTableColumnDefinitionGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateColumnAssignmentSymbolBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateSetGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnRawGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlDataTypeParamBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlFunctionParamBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlInsertColumnGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlParallelListBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlRightPatternBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlViewGroupBlock +import org.domaframework.doma.intellij.formatter.builder.SqlBlockBuilder +import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder +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.SqlBlockUtil import org.domaframework.doma.intellij.psi.SqlTypes open class SqlBlock( @@ -65,7 +75,16 @@ open class SqlBlock( ) { data class ElementIndent( var indentLevel: IndentType, + /** + * The number of indentation spaces for this element. + * Returns `0` if there is no line break. + */ var indentLen: Int, + /** + * Indentation baseline applied to the group itself. + * Even if the group does not start on a new line, + * it determines and applies indentation to the group based on factors such as the number of preceding characters. + */ var groupIndentLen: Int, ) @@ -80,17 +99,23 @@ open class SqlBlock( ) private val blockBuilder = SqlBlockBuilder() + private val parentSetProcessor = SqlSetParentGroupProcessor(blockBuilder) protected val blockUtil = SqlBlockUtil(this, isEnableFormat(), formatMode) protected open val pendingCommentBlocks = mutableListOf() fun isEnableFormat(): Boolean = enableFormat - open fun setParentGroupBlock(block: SqlBlock?) { - parentBlock = block + open fun setParentGroupBlock(lastGroup: SqlBlock?) { + parentBlock = lastGroup parentBlock?.addChildBlock(this) + setParentPropertyBlock(lastGroup) } + open fun setParentPropertyBlock(lastGroup: SqlBlock?) {} + + open val isNeedWhiteSpace: Boolean = true + open fun addChildBlock(childBlock: SqlBlock) { childBlocks.add(childBlock) } @@ -102,33 +127,16 @@ open class SqlBlock( var child = node.firstChildNode var prevNonWhiteSpaceNode: ASTNode? = null - blockBuilder.addGroupTopNodeIndexHistory(Pair(0, this)) + blockBuilder.addGroupTopNodeIndexHistory(this) while (child != null) { val lastBlock = blocks.lastOrNull() - val lastGroup = blockBuilder.getLastGroupTopNodeIndexHistory()?.second + val lastGroup = blockBuilder.getLastGroupTopNodeIndexHistory() if (child !is PsiWhiteSpace) { val childBlock = getBlock(child) - if (blocks.isNotEmpty() && lastBlock is SqlWhitespaceBlock) { - if (isSaveWhiteSpace(childBlock, child, lastGroup)) { - val whiteBlock = lastBlock as SqlBlock - whiteBlock.parentBlock = lastGroup - } else { - // Ignore space blocks for non-breaking elements - blocks.removeLast() - } - } + updateWhiteSpaceInclude(lastBlock, childBlock, lastGroup) prevNonWhiteSpaceNode = child - if (childBlock is SqlCommentBlock) { - when (childBlock) { - is SqlElConditionLoopCommentBlock -> - blockBuilder.addConditionOrLoopBlock( - childBlock, - ) - - else -> blockBuilder.addCommentBlock(childBlock) - } - } - updateSearchKeywordLevelHistory(childBlock, child) + updateCommentParentAndIdent(childBlock) + updateBlockParentAndLAddGroup(childBlock) blocks.add(childBlock) } else { if (lastBlock !is SqlLineCommentBlock) { @@ -150,404 +158,279 @@ open class SqlBlock( return blocks } - private fun isSaveWhiteSpace( + /** + * Sets the parent and indentation for the comment element based on the element that was registered earlier. + */ + private fun updateCommentParentAndIdent(commentBlock: SqlBlock) { + if (commentBlock !is SqlCommentBlock) return + if (commentBlock is SqlElConditionLoopCommentBlock) { + blockBuilder.addConditionOrLoopBlock( + commentBlock, + ) + } else { + blockBuilder.addCommentBlock(commentBlock) + } + } + + /** + * Determines whether to retain the preceding newline (space) as a formatting target block based on the currently checked element. + */ + private fun updateWhiteSpaceInclude( + lastBlock: AbstractBlock?, childBlock: SqlBlock, - child: ASTNode, lastGroup: SqlBlock?, - ): Boolean = - isNewLineGroupBlock(childBlock, child, lastGroup) || - childBlock is SqlInsertColumnGroupBlock || - childBlock is SqlColumnDefinitionRawGroupBlock || - childBlock is SqlColumnDefinitionGroupBlock || - (childBlock is SqlOtherBlock && childBlock.isUpdateColumnSubstitutions) || - (childBlock is SqlRightPatternBlock && childBlock.isNewLine(lastGroup)) || - ( - ( - childBlock is SqlLineCommentBlock || - childBlock is SqlBlockCommentBlock - ) && - child.treePrev.text.contains("\n") - ) || - (childBlock is SqlElConditionLoopCommentBlock) - - private fun isNewGroup(childBlock: SqlBlock): Boolean { - val isNewGroupType = childBlock.indent.indentLevel.isNewLineGroup() - val lastGroup = blockBuilder.getLastGroupTopNodeIndexHistory()?.second - val lastKeywordText = - if (lastGroup?.indent?.indentLevel == IndentType.JOIN) { - lastGroup.getNodeText() + ) { + if (blocks.isNotEmpty() && lastBlock is SqlWhitespaceBlock) { + if (isSaveWhiteSpace(childBlock, lastGroup)) { + val whiteBlock = lastBlock as SqlBlock + whiteBlock.parentBlock = lastGroup } else { - getLastGroupKeywordText(lastGroup) + // Ignore space blocks for non-breaking elements + blocks.removeLast() } + } + } - val isSetLineGroup = - SqlKeywordUtil.isSetLineKeyword( - childBlock.getNodeText(), - lastKeywordText, + /** + * Determines whether to retain the space (newline) based on the last registered group or the class of the currently checked element. + */ + private fun isSaveWhiteSpace( + childBlock: SqlBlock, + lastGroup: SqlBlock?, + ): Boolean { + val child = childBlock.node + + if (!childBlock.isNeedWhiteSpace) return false + + val expectedClassTypes = + listOf( + SqlElConditionLoopCommentBlock::class, + SqlInsertColumnGroupBlock::class, + SqlColumnDefinitionRawGroupBlock::class, + SqlCreateTableColumnDefinitionGroupBlock::class, + SqlUpdateColumnAssignmentSymbolBlock::class, ) - return isNewGroupType && !isSetLineGroup + if (isExpectedClassType(expectedClassTypes, childBlock)) return true + + if (isNewLineSqlComment(child, childBlock)) return true + + return ( + isNewLineGroupBlockAfterRegistrationChild(childBlock, lastGroup) || + (childBlock is SqlRightPatternBlock && childBlock.isNewLine(lastGroup)) + ) } - private fun isNewLineGroupBlock( - childBlock: SqlBlock, + /** + * Retains the block only for comments that are broken down. + */ + private fun isNewLineSqlComment( child: ASTNode, - lastGroup: SqlBlock?, + childBlock: SqlBlock, ): Boolean { - if (childBlock is SqlCommaBlock && - ( - lastGroup is SqlParallelListBlock || - lastGroup?.parentBlock is SqlParallelListBlock + val commentBlockType = + listOf( + SqlLineCommentBlock::class, + SqlBlockCommentBlock::class, ) - ) { - return false - } + val prevSpace = PsiTreeUtil.prevLeaf(child.psi) + return isExpectedClassType( + commentBlockType, + childBlock, + ) && + prevSpace?.text?.contains("\n") == true + } - val isNewGroupType = childBlock.indent.indentLevel.isNewLineGroup() - val lastKeywordText = - if (lastGroup?.indent?.indentLevel == IndentType.JOIN) { - lastGroup.getNodeText() - } else { - getLastGroupKeywordText(lastGroup) - } + /** + * Determines whether a newline is required after registering itself as a child of the parent block. + */ + private fun isNewLineGroupBlockAfterRegistrationChild( + childBlock: SqlBlock, + lastGroup: SqlBlock?, + ): Boolean { + fun isParallelListRawChild(): Boolean = + childBlock is SqlCommaBlock && + ( + lastGroup is SqlParallelListBlock || + lastGroup?.parentBlock is SqlParallelListBlock + ) - val isSetLineGroup = - SqlKeywordUtil.isSetLineKeyword( - child.text, - lastKeywordText, - ) - if (isNewGroupType && !isSetLineGroup) { - if (lastGroup is SqlSubQueryGroupBlock) { - return (lastGroup.childBlocks.size > 1) + if (isParallelListRawChild()) return false + + if (parentSetProcessor.isNewGroupAndNotSetLineKeywords(childBlock, lastGroup)) { + return if (lastGroup is SqlSubQueryGroupBlock) { + val lastGroupChildren = lastGroup.childBlocks + (lastGroupChildren.isNotEmpty() && lastGroupChildren.drop(1).isNotEmpty()) + } else { + true } - return true } return false } /** - * Searches for a keyword element in the most recent group block and returns its text. - * If not found, returns the text of the group block itself. + * Updates the parent block or registers itself as a new group block based on the class of the target block. */ - private fun getLastGroupKeywordText(lastGroup: SqlBlock?): String = - lastGroup - ?.childBlocks - ?.lastOrNull { it.node.elementType == SqlTypes.KEYWORD } - ?.node - ?.text ?: lastGroup?.getNodeText() ?: "" - - protected open fun updateSearchKeywordLevelHistory( - childBlock: SqlBlock, - child: ASTNode, - ) { - val lastGroupBlock = blockBuilder.getLastGroupTopNodeIndexHistory()?.second + private fun updateBlockParentAndLAddGroup(childBlock: SqlBlock) { + val lastGroupBlock = blockBuilder.getLastGroupTopNodeIndexHistory() val lastIndentLevel = lastGroupBlock?.indent?.indentLevel if (lastGroupBlock == null || lastIndentLevel == null) { - setParentGroups( + parentSetProcessor.updateGroupBlockAddGroup( childBlock, - ) { history -> - return@setParentGroups null - } + ) return } when (childBlock) { is SqlKeywordGroupBlock -> { - if (lastGroupBlock.indent.indentLevel == IndentType.SUB) { - setParentGroups( - childBlock, - ) { history -> - return@setParentGroups lastGroupBlock - } - } else if (lastIndentLevel == childBlock.indent.indentLevel) { - blockBuilder.removeLastGroupTopNodeIndexHistory() - setParentGroups( - childBlock, - ) { history -> - return@setParentGroups lastGroupBlock.parentBlock - } - } else if (lastIndentLevel < childBlock.indent.indentLevel) { - setParentGroups( - childBlock, - ) { history -> - return@setParentGroups history.last().second - } - } else { - if (lastIndentLevel == IndentType.JOIN && - SqlKeywordUtil.isSecondOptionKeyword(child.text) - ) { - // left,right < inner,outer < join - setParentGroups( - childBlock, - ) { history -> - return@setParentGroups history.last().second - } - return - } - - setParentGroups( - childBlock, - ) { history -> - return@setParentGroups history - .lastOrNull { it.second.indent.indentLevel < childBlock.indent.indentLevel } - ?.second - } - } + parentSetProcessor.updateKeywordGroupBlockParentAndAddGroup( + lastGroupBlock, + lastIndentLevel, + childBlock, + ) } - is SqlColumnGroupBlock -> { - when (lastIndentLevel) { - childBlock.indent.indentLevel -> { - blockBuilder.removeLastGroupTopNodeIndexHistory() - setParentGroups( - childBlock, - ) { history -> - return@setParentGroups lastGroupBlock.parentBlock - } - } + is SqlColumnDefinitionRawGroupBlock -> { + parentSetProcessor.updateColumnDefinitionRawGroupBlockParentAndAddGroup( + lastGroupBlock, + lastIndentLevel, + childBlock, + ) + } - else -> { - setParentGroups( - childBlock, - ) { history -> - return@setParentGroups history.last().second - } - } - } + is SqlColumnRawGroupBlock -> { + parentSetProcessor.updateColumnRawGroupBlockParentAndAddGroup( + lastGroupBlock, + childBlock, + ) } is SqlInlineGroupBlock -> { // case-end - setParentGroups( + parentSetProcessor.updateGroupBlockParentAndAddGroup( childBlock, - ) { history -> - return@setParentGroups history.last().second - } + ) } is SqlInlineSecondGroupBlock -> { - if (childBlock.isEndCase) { - val inlineIndex = - blockBuilder.getGroupTopNodeIndex { block -> - block.indent.indentLevel == IndentType.INLINE - } - if (inlineIndex >= 0) { - setParentGroups( - childBlock, - ) { history -> - return@setParentGroups history[inlineIndex].second - } - blockBuilder.clearSubListGroupTopNodeIndexHistory(inlineIndex) - } - return - } - if (lastIndentLevel == IndentType.INLINE_SECOND) { - blockBuilder.removeLastGroupTopNodeIndexHistory() - setParentGroups( - childBlock, - ) { history -> - return@setParentGroups lastGroupBlock.parentBlock - } - return - } - setParentGroups( + parentSetProcessor.updateInlineSecondGroupBlockParentAndAddGroup( + lastGroupBlock, + lastIndentLevel, childBlock, - ) { history -> - return@setParentGroups history.last().second - } + ) } is SqlColumnBlock -> { - setParentGroups( - childBlock, - ) { history -> - val parentGroupBlock = history.last().second - if (parentGroupBlock is SqlColumnDefinitionRawGroupBlock && - parentGroupBlock.columnName != "," - ) { - parentGroupBlock.columnName = childBlock.getNodeText() - val columnDefinition = - parentGroupBlock.parentBlock as? SqlColumnDefinitionGroupBlock - if (columnDefinition != null && columnDefinition.alignmentColumnName.length < parentGroupBlock.columnName.length) { - columnDefinition.alignmentColumnName = parentGroupBlock.columnName - } - } - return@setParentGroups history.last().second - } - } - - is SqlColumnDefinitionRawGroupBlock -> { - if (lastGroupBlock is SqlColumnDefinitionRawGroupBlock) { - blockBuilder.removeLastGroupTopNodeIndexHistory() - } - setParentGroups( + parentSetProcessor.updateGroupBlockParentAndAddGroup( childBlock, - ) { history -> - return@setParentGroups history.last().second - } + ) } is SqlElConditionLoopCommentBlock -> { - if (lastGroupBlock is SqlCommaBlock || lastGroupBlock is SqlElConditionLoopCommentBlock) { - blockBuilder.removeLastGroupTopNodeIndexHistory() - } - setParentGroups( + parentSetProcessor.updateConditionLoopCommentBlockParent( + lastGroupBlock, childBlock, - ) { history -> - if (childBlock.conditionType.isEnd()) { - val lastConditionLoopCommentBlock = blockBuilder.getConditionOrLoopBlocksLast() - blockBuilder.removeConditionOrLoopBlockLast() - return@setParentGroups lastConditionLoopCommentBlock - } - return@setParentGroups null - } + ) } is SqlWordBlock, is SqlOtherBlock, is SqlLineCommentBlock, is SqlBlockCommentBlock -> { - setParentGroups( + parentSetProcessor.updateGroupBlockParentAndAddGroup( childBlock, - ) { history -> - return@setParentGroups history.last().second - } + ) } is SqlSubQueryGroupBlock -> { - setParentGroups( + parentSetProcessor.updateGroupBlockParentAndAddGroup( childBlock, - ) { history -> - return@setParentGroups history.last().second - } + ) } is SqlRightPatternBlock -> { - val paramIndex = - blockBuilder.getGroupTopNodeIndex { block -> - block.indent.indentLevel == IndentType.PARAM - } - if (paramIndex >= 0) { - setParentGroups( - childBlock, - ) { history -> - return@setParentGroups history[paramIndex].second - } - blockBuilder.clearSubListGroupTopNodeIndexHistory(paramIndex) - return - } - - val leftIndex = - blockBuilder.getGroupTopNodeIndex { block -> - block.indent.indentLevel == IndentType.SUB - } - if (leftIndex >= 0) { - setParentGroups( - childBlock, - ) { history -> - return@setParentGroups history[leftIndex].second - } - blockBuilder.clearSubListGroupTopNodeIndexHistory(leftIndex) - return - } + parentSetProcessor.updateSqlRightPatternBlockParent( + childBlock, + ) } is SqlElSymbolBlock -> { - setParentGroups( + parentSetProcessor.updateGroupBlockParentAndAddGroup( childBlock, - ) { history -> - return@setParentGroups history.last().second - } + ) } is SqlDataTypeBlock -> { - setParentGroups( + parentSetProcessor.updateGroupBlockParentAndAddGroup( childBlock, - ) { history -> - return@setParentGroups history.last().second - } + ) } is SqlCommaBlock -> { if (lastGroupBlock is SqlCommaBlock) { blockBuilder.removeLastGroupTopNodeIndexHistory() } - setParentGroups( + parentSetProcessor.updateGroupBlockParentAndAddGroup( childBlock, - ) { history -> - return@setParentGroups history.last().second - } + ) } else -> { - setParentGroups( + parentSetProcessor.updateGroupBlockParentAndAddGroup( childBlock, - ) { history -> - return@setParentGroups history.last().second - } + ) } } } - private fun setParentGroups( - childBlock: SqlBlock, - getParentGroup: (MutableList>) -> SqlBlock?, - ) { - val parentGroup = - getParentGroup(blockBuilder.getGroupTopNodeIndexHistory() as MutableList>) - - // // The parent block for SqlElConditionLoopCommentBlock will be set later - if (childBlock !is SqlElConditionLoopCommentBlock || - childBlock.conditionType.isEnd() - ) { - childBlock.setParentGroupBlock(parentGroup) - } - - if (isNewGroup(childBlock) || - (childBlock is SqlSubGroupBlock) || - childBlock is SqlViewGroupBlock || - childBlock is SqlInlineGroupBlock || - childBlock is SqlInlineSecondGroupBlock || - childBlock is SqlColumnDefinitionRawGroupBlock - ) { - blockBuilder.addGroupTopNodeIndexHistory(Pair(blocks.size - 1, childBlock)) - // Set parent-child relationship and indent for preceding comment at beginning of block group - blockBuilder.updateCommentBlockIndent(childBlock) - } - } - + /** + * Creates the indentation length for the block. + */ open fun createBlockIndentLen(): Int = 0 + /** + * Creates a block for the given child AST node. + */ open fun getBlock(child: ASTNode): SqlBlock { - val lastGroup = blockBuilder.getLastGroupTopNodeIndexHistory()?.second + val defaultFormatCtx = + SqlBlockFormattingContext( + wrap, + alignment, + spacingBuilder, + isEnableFormat(), + formatMode, + ) + val lastGroup = blockBuilder.getLastGroupTopNodeIndexHistory() return when (child.elementType) { SqlTypes.KEYWORD -> { return blockUtil.getKeywordBlock( child, - blockBuilder.getLastGroupTopNodeIndexHistory()?.second, + blockBuilder.getLastGroupTopNodeIndexHistory(), ) } - SqlTypes.DATATYPE -> SqlDataTypeBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + SqlTypes.DATATYPE -> { + SqlDataTypeBlock( + child, + defaultFormatCtx, + ) + } SqlTypes.LEFT_PAREN -> { return blockUtil.getSubGroupBlock(lastGroup, child) } - SqlTypes.OTHER -> return SqlOtherBlock( - child, - wrap, - alignment, - spacingBuilder, - blockBuilder.getLastGroup(), - isEnableFormat(), - formatMode, - ) + SqlTypes.OTHER -> return if (lastGroup is SqlUpdateSetGroupBlock && + lastGroup.columnDefinitionGroupBlock != null + ) { + SqlUpdateColumnAssignmentSymbolBlock(child, defaultFormatCtx) + } else { + SqlOtherBlock( + child, + defaultFormatCtx, + ) + } SqlTypes.RIGHT_PAREN -> return SqlRightPatternBlock( child, - wrap, - alignment, - spacingBuilder, - isEnableFormat(), - formatMode, + defaultFormatCtx, ) SqlTypes.COMMA -> { @@ -561,23 +444,45 @@ open class SqlBlock( } SqlTypes.LINE_COMMENT -> - return SqlLineCommentBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + return SqlLineCommentBlock( + child, + defaultFormatCtx, + ) SqlTypes.PLUS, SqlTypes.MINUS, SqlTypes.ASTERISK, SqlTypes.SLASH -> - return SqlElSymbolBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + return SqlElSymbolBlock( + child, + defaultFormatCtx, + ) SqlTypes.LE, SqlTypes.LT, SqlTypes.EL_EQ, SqlTypes.EL_NE, SqlTypes.GE, SqlTypes.GT -> - return SqlElSymbolBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + return SqlElSymbolBlock( + child, + defaultFormatCtx, + ) SqlTypes.STRING, SqlTypes.NUMBER, SqlTypes.BOOLEAN -> - return SqlLiteralBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + return SqlLiteralBlock( + child, + defaultFormatCtx, + ) - else -> SqlUnknownBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + else -> + SqlUnknownBlock( + child, + defaultFormatCtx, + ) } } + /** + * Creates a spacing builder for custom spacing rules. + */ protected open fun createSpacingBuilder(): SqlCustomSpacingBuilder = SqlCustomSpacingBuilder() + /** + * Creates a spacing builder specifically for block comments. + */ protected fun createBlockCommentSpacingBuilder(): SqlCustomSpacingBuilder = SqlCustomSpacingBuilder() .withSpacing( @@ -606,6 +511,9 @@ open class SqlBlock( Spacing.createSpacing(0, 0, 0, true, 0), ) + /** + * Returns the indentation for the block. + */ override fun getIndent(): Indent? = if (isAdjustIndentOnEnter()) { null @@ -613,8 +521,14 @@ open class SqlBlock( Indent.getSpaceIndent(indent.indentLen) } - protected fun isAdjustIndentOnEnter(): Boolean = formatMode == FormattingMode.ADJUST_INDENT_ON_ENTER && !isEnableFormat() + /** + * Determines whether to adjust the indentation on pressing Enter. + */ + fun isAdjustIndentOnEnter(): Boolean = formatMode == FormattingMode.ADJUST_INDENT_ON_ENTER && !isEnableFormat() + /** + * Returns the spacing between two child blocks. + */ override fun getSpacing( child1: Block?, child2: Block, @@ -633,11 +547,7 @@ open class SqlBlock( if (child2 is SqlElBlockCommentBlock) { return when (child1) { - is SqlElBlockCommentBlock -> { - SqlCustomSpacingBuilder().getSpacing(child2) - } - - is SqlWhitespaceBlock -> { + is SqlElBlockCommentBlock, is SqlWhitespaceBlock -> { SqlCustomSpacingBuilder().getSpacing(child2) } @@ -655,11 +565,7 @@ open class SqlBlock( if (child1 is SqlWhitespaceBlock) { when (child2) { - is SqlBlockCommentBlock, is SqlLineCommentBlock -> { - return SqlCustomSpacingBuilder().getSpacing(child2) - } - - is SqlNewGroupBlock -> { + is SqlBlockCommentBlock, is SqlLineCommentBlock, is SqlNewGroupBlock -> { return SqlCustomSpacingBuilder().getSpacing(child2) } } @@ -679,30 +585,37 @@ open class SqlBlock( } } - if (child2 is SqlColumnDefinitionRawGroupBlock) { - SqlCustomSpacingBuilder().getSpacingColumnDefinitionRaw(child2)?.let { return it } - } + // Create Table Column Definition Raw Group Block + CreateTableUtil.getColumnDefinitionRawGroupSpacing(child1, child2)?.let { return it } - if (child2 is SqlRightPatternBlock) { - return SqlCustomSpacingBuilder().getSpacingRightPattern(child2) - } + when (child2) { + is SqlColumnDefinitionRawGroupBlock -> + SqlCustomSpacingBuilder() + .getSpacingColumnDefinitionRaw( + child2, + )?.let { return it } - if (child1 is SqlBlock && (child2 is SqlCommaBlock || child2 is SqlColumnGroupBlock)) { - SqlCustomSpacingBuilder().getSpacingWithIndentComma(child1, child2)?.let { return it } - } + is SqlRightPatternBlock -> return SqlCustomSpacingBuilder().getSpacingRightPattern( + child2, + ) - if (child2 is SqlDataTypeParamBlock) { - return SqlCustomSpacingBuilder.nonSpacing + is SqlColumnBlock -> + SqlCustomSpacingBuilder() + .getSpacingColumnDefinition(child2) + ?.let { return it } } - if (child2 is SqlColumnBlock) { - SqlCustomSpacingBuilder().getSpacingColumnDefinition(child2)?.let { return it } + if (child1 is SqlBlock && (child2 is SqlCommaBlock || child2 is SqlColumnRawGroupBlock)) { + SqlCustomSpacingBuilder().getSpacingWithIndentComma(child1, child2)?.let { return it } } val spacing: Spacing? = customSpacingBuilder?.getCustomSpacing(child1, child2) return spacing ?: spacingBuilder.getSpacing(this, child1, child2) } + /** + * Returns the child attributes for a new child at the specified index. + */ override fun getChildAttributes(newChildIndex: Int): ChildAttributes { if (!isEnableFormat()) return ChildAttributes(Indent.getNoneIndent(), null) @@ -719,6 +632,9 @@ open class SqlBlock( return ChildAttributes(Indent.getNoneIndent(), null) } + /** + * Returns the child indentation for the block. + */ override fun getChildIndent(): Indent? = if (isEnableFormat()) { Indent.getSpaceIndent(4) @@ -726,5 +642,8 @@ open class SqlBlock( Indent.getSpaceIndent(0) } + /** + * Determines whether the block is a leaf node. + */ override fun isLeaf(): Boolean = myNode.firstChildNode == null } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlBlockCommentBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlBlockCommentBlock.kt index edb94215..829ab17b 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlBlockCommentBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlBlockCommentBlock.kt @@ -13,26 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block +package org.domaframework.doma.intellij.formatter.block.comment -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext open class SqlBlockCommentBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlCommentBlock( node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlColumnBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlColumnBlock.kt index d89152c8..492a58b6 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlColumnBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlColumnBlock.kt @@ -13,31 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block +package org.domaframework.doma.intellij.formatter.block.group.column -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnDefinitionGroupBlock +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.SqlWordBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateTableColumnDefinitionGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext class SqlColumnBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlWordBlock( node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override val indent = ElementIndent( @@ -46,22 +37,26 @@ class SqlColumnBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.NONE // Calculate right justification space during indentation after getting all column rows indent.indentLen = 1 indent.groupIndentLen = 0 } + override fun setParentPropertyBlock(lastGroup: SqlBlock?) { + (lastGroup as? SqlColumnDefinitionRawGroupBlock)?.columnBlock = this + } + override fun buildChildren(): MutableList = mutableListOf() override fun createBlockIndentLen(): Int { parentBlock?.let { - val parentGroupDefinition = it.parentBlock as? SqlColumnDefinitionGroupBlock + val parentGroupDefinition = it.parentBlock as? SqlCreateTableColumnDefinitionGroupBlock if (parentGroupDefinition == null) return 1 - val groupMaxAlimentLen = parentGroupDefinition.alignmentColumnName.length + val groupMaxAlimentLen = parentGroupDefinition.getMaxColumnNameLength() val diffColumnName = groupMaxAlimentLen.minus(getNodeText().length) return diffColumnName.plus(1) } 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 cfe8afbf..c378d92d 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 @@ -15,37 +15,30 @@ */ package org.domaframework.doma.intellij.formatter.block -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType -import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlCreateKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInsertKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertQueryGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnRawGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlParallelListBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateColumnGroupBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateValueGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext import org.domaframework.doma.intellij.psi.SqlTypes open class SqlCommaBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlBlock( node, - wrap, - alignment, + context.wrap, + context.alignment, null, - spacingBuilder, - enableFormat, - formatMode, + context.spacingBuilder, + context.enableFormat, + context.formatMode, ) { override val indent = ElementIndent( @@ -54,8 +47,8 @@ open class SqlCommaBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.COMMA indent.indentLen = createBlockIndentLen() indent.groupIndentLen = indent.indentLen.plus(getNodeText().length) @@ -81,10 +74,10 @@ open class SqlCommaBlock( val grandIndentLen = grand.indent.groupIndentLen return grandIndentLen.plus(parentIndentLen).minus(1) } - if (grand is SqlInsertKeywordGroupBlock) { + if (grand is SqlInsertQueryGroupBlock) { return parentIndentLen } - if (grand is SqlColumnGroupBlock) { + if (grand is SqlColumnRawGroupBlock) { val grandIndentLen = grand.indent.groupIndentLen var prevTextLen = 1 parent.prevChildren?.dropLast(1)?.forEach { prev -> prevTextLen = prevTextLen.plus(prev.getNodeText().length) } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlCommentBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlCommentBlock.kt index 1401ecbb..5e6d1d2f 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlCommentBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlCommentBlock.kt @@ -13,32 +13,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block +package org.domaframework.doma.intellij.formatter.block.comment -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType +import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext abstract class SqlCommentBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlBlock( node, - wrap, - alignment, + context.wrap, + context.alignment, null, - spacingBuilder, - enableFormat, - formatMode, + context.spacingBuilder, + context.enableFormat, + context.formatMode, ) { override val indent = ElementIndent( @@ -47,8 +41,8 @@ abstract class SqlCommentBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.NONE indent.indentLen = createBlockIndentLen() indent.groupIndentLen = 0 diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlDataTypeBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlDataTypeBlock.kt index fb58e872..716e72e4 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlDataTypeBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlDataTypeBlock.kt @@ -13,31 +13,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block +package org.domaframework.doma.intellij.formatter.block.group.column -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateTableColumnDefinitionRawGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext open class SqlDataTypeBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlBlock( node, - wrap, - alignment, + context.wrap, + context.alignment, null, - spacingBuilder, - enableFormat, - formatMode, + context.spacingBuilder, + context.enableFormat, + context.formatMode, ) { override val indent = ElementIndent( @@ -46,11 +41,15 @@ open class SqlDataTypeBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroupBlock: SqlBlock?) { + super.setParentGroupBlock(lastGroupBlock) indent.indentLevel = IndentType.NONE indent.indentLen = 1 indent.groupIndentLen = indent.indentLen + + if (lastGroupBlock is SqlCreateTableColumnDefinitionRawGroupBlock) { + lastGroupBlock.columnDataTypeBlock = this + } } override fun buildChildren(): MutableList = mutableListOf() 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 82fa7653..8402e58d 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 @@ -15,32 +15,18 @@ */ package org.domaframework.doma.intellij.formatter.block -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Indent -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext open class SqlKeywordBlock( node: ASTNode, val indentLevel: IndentType = IndentType.ATTACHED, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, -) : SqlNewGroupBlock( - node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, - ) { + context: SqlBlockFormattingContext, +) : SqlNewGroupBlock(node, context) { override val indent = ElementIndent( indentLevel, @@ -48,14 +34,20 @@ open class SqlKeywordBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = indentLevel indent.indentLen = createBlockIndentLen() indent.groupIndentLen = indent.indentLen.plus(getNodeText().length) } +// override fun setParentPropertyBlock(lastGroup: SqlBlock?) { +// if (getNodeText() == "nothing" && lastGroup is SqlDoGroupBlock) { +// lastGroup.doQueryBlock = this +// } +// } + override fun buildChildren(): MutableList = mutableListOf() override fun getIndent(): Indent? { diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlLineCommentBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlLineCommentBlock.kt index 718cf03c..77b3d221 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlLineCommentBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlLineCommentBlock.kt @@ -13,33 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block +package org.domaframework.doma.intellij.formatter.block.comment -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock +import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext open class SqlLineCommentBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlCommentBlock( node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLen = createBlockIndentLen() } @@ -48,16 +38,16 @@ open class SqlLineCommentBlock( override fun isLeaf(): Boolean = true override fun createBlockIndentLen(): Int { - parentBlock?.let { - if (it is SqlSubQueryGroupBlock) { - if (it.childBlocks.dropLast(1).isEmpty()) { + parentBlock?.let { parent -> + if (parent is SqlSubQueryGroupBlock) { + if (parent.childBlocks.dropLast(1).isEmpty()) { return 1 } - if (it.isFirstLineComment) { - return it.indent.groupIndentLen.minus(2) + if (parent.isFirstLineComment) { + return parent.indent.groupIndentLen.minus(2) } } - return it.indent.indentLen + return parent.indent.indentLen } return 1 } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlLiteralBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlLiteralBlock.kt index 37c61eae..1b73c78e 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlLiteralBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlLiteralBlock.kt @@ -15,29 +15,22 @@ */ package org.domaframework.doma.intellij.formatter.block -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext open class SqlLiteralBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlBlock( node, - wrap, - alignment, + context.wrap, + context.alignment, null, - spacingBuilder, - enableFormat, - formatMode, + context.spacingBuilder, + context.enableFormat, + context.formatMode, ) { override val indent = ElementIndent( @@ -46,8 +39,8 @@ open class SqlLiteralBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.NONE indent.indentLen = 0 indent.groupIndentLen = 0 diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlOperationBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlOperationBlock.kt index 95a75756..703ca9ae 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlOperationBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlOperationBlock.kt @@ -15,29 +15,18 @@ */ package org.domaframework.doma.intellij.formatter.block -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.expr.SqlElSymbolBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext class SqlOperationBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlElSymbolBlock( node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override val indent = ElementIndent( @@ -46,8 +35,8 @@ class SqlOperationBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.NONE indent.indentLen = 0 indent.groupIndentLen = 0 diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlOtherBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlOtherBlock.kt index ab4c1ba1..f46c402c 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlOtherBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlOtherBlock.kt @@ -15,34 +15,23 @@ */ package org.domaframework.doma.intellij.formatter.block -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateColumnGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext open class SqlOtherBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - lastGroup: SqlBlock? = null, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlBlock( node, - wrap, - alignment, + context.wrap, + context.alignment, null, - spacingBuilder, - enableFormat, - formatMode, + context.spacingBuilder, + context.enableFormat, + context.formatMode, ) { - var isUpdateColumnSubstitutions = isBeforeUpdateValuesBlock(lastGroup) - override val indent = ElementIndent( IndentType.NONE, @@ -50,8 +39,10 @@ open class SqlOtherBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override val isNeedWhiteSpace: Boolean = false + + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.NONE indent.indentLen = createIndentLen() indent.groupIndentLen = 0 @@ -59,17 +50,7 @@ open class SqlOtherBlock( override fun buildChildren(): MutableList = mutableListOf() - private fun createIndentLen(): Int { - if (isUpdateColumnSubstitutions) { - parentBlock?.let { return it.indent.groupIndentLen.plus(1) } - ?: return indent.indentLen - } else { - return 1 - } - } - - fun isBeforeUpdateValuesBlock(lastGroupBlock: SqlBlock?): Boolean = - lastGroupBlock?.childBlocks?.lastOrNull() is SqlUpdateColumnGroupBlock + private fun createIndentLen(): Int = 1 override fun isLeaf(): Boolean = true } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlRightPatternBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlRightPatternBlock.kt index 85b2c086..d71640fc 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 @@ -13,55 +13,51 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block +package org.domaframework.doma.intellij.formatter.block.group.subgroup -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType -import org.domaframework.doma.intellij.formatter.block.group.SqlColumnDefinitionRawGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInsertKeywordGroupBlock +import org.domaframework.doma.intellij.common.util.TypeUtil.isExpectedClassType +import org.domaframework.doma.intellij.formatter.block.SqlBlock +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.SqlUpdateKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnDefinitionGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlFunctionParamBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlInsertColumnGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateColumnGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateValueGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateTableColumnDefinitionGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertQueryGroupBlock +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.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext /** * Parent is always a subclass of a subgroup */ open class SqlRightPatternBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlBlock( node, - wrap, - alignment, + context.wrap, + context.alignment, null, - spacingBuilder, - enableFormat, - formatMode, + context.spacingBuilder, + context.enableFormat, + context.formatMode, ) { var preSpaceRight = false + /** + * Configures whether to add a space to the right side when the group ends. + */ fun enableLastRight() { parentBlock?.let { parent -> - // TODO:Customize indentation - if (parent is SqlFunctionParamBlock) { - preSpaceRight = false - return - } - if (parent is SqlInsertColumnGroupBlock) { + // TODO:Customize spacing + val notInsertSpaceClassList = + listOf( + SqlFunctionParamBlock::class, + SqlInsertColumnGroupBlock::class, + ) + if (isExpectedClassType(notInsertSpaceClassList, parent)) { preSpaceRight = false return } @@ -80,7 +76,7 @@ open class SqlRightPatternBlock( parent.parentBlock?.let { grand -> preSpaceRight = ( grand.indent.indentLevel <= IndentType.SECOND && - grand.parentBlock !is SqlInsertKeywordGroupBlock + grand.parentBlock !is SqlInsertQueryGroupBlock ) || grand.indent.indentLevel == IndentType.JOIN return @@ -96,12 +92,13 @@ open class SqlRightPatternBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.NONE indent.indentLen = createBlockIndentLen() indent.groupIndentLen = indent.indentLen enableLastRight() + (lastGroup as? SqlSubGroupBlock)?.endPatternBlock = this } override fun buildChildren(): MutableList = mutableListOf() @@ -116,9 +113,9 @@ open class SqlRightPatternBlock( override fun isLeaf(): Boolean = true fun isNewLine(lastGroup: SqlBlock?): Boolean = - lastGroup is SqlColumnDefinitionGroupBlock || + lastGroup is SqlCreateTableColumnDefinitionGroupBlock || lastGroup is SqlColumnDefinitionRawGroupBlock || - lastGroup?.parentBlock is SqlUpdateKeywordGroupBlock || + lastGroup?.parentBlock is SqlUpdateSetGroupBlock || lastGroup?.parentBlock is SqlUpdateColumnGroupBlock || lastGroup is SqlUpdateColumnGroupBlock || lastGroup is SqlUpdateValueGroupBlock || diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlTableBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlTableBlock.kt index df223871..982eec04 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlTableBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlTableBlock.kt @@ -15,27 +15,30 @@ */ package org.domaframework.doma.intellij.formatter.block -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.util.CreateQueryType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext class SqlTableBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlWordBlock( node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { + override val isNeedWhiteSpace = false + + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) + } + + override fun setParentPropertyBlock(lastGroup: SqlBlock?) { + if (lastGroup is SqlCreateKeywordGroupBlock && lastGroup.createType == CreateQueryType.TABLE) { + lastGroup.tableBlock = this + } + } + override fun buildChildren(): MutableList = mutableListOf() } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlUnknownBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlUnknownBlock.kt index 5f477cda..0836dc9b 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlUnknownBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlUnknownBlock.kt @@ -15,32 +15,25 @@ */ package org.domaframework.doma.intellij.formatter.block -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext class SqlUnknownBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlBlock( node, - wrap, - alignment, + context.wrap, + context.alignment, null, - spacingBuilder, - enableFormat, - formatMode, + context.spacingBuilder, + context.enableFormat, + context.formatMode, ) { - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.NONE indent.indentLen = 0 indent.groupIndentLen = 0 diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlWordBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlWordBlock.kt index d6e6ab4e..6d3e941b 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlWordBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlWordBlock.kt @@ -15,30 +15,23 @@ */ package org.domaframework.doma.intellij.formatter.block -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext open class SqlWordBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlBlock( node, - wrap, - alignment, + context.wrap, + context.alignment, null, - spacingBuilder, - enableFormat, - formatMode, + context.spacingBuilder, + context.enableFormat, + context.formatMode, ) { override val indent = ElementIndent( @@ -47,8 +40,8 @@ open class SqlWordBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLen = createBlockIndentLen() indent.groupIndentLen = indent.indentLen } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElAtSignBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElAtSignBlock.kt index d13912f2..c6b868c2 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElAtSignBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElAtSignBlock.kt @@ -15,33 +15,20 @@ */ package org.domaframework.doma.intellij.formatter.block.expr -import com.intellij.formatting.Alignment import com.intellij.formatting.Block -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Spacing -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.SqlCustomSpacingBuilder -import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext class SqlElAtSignBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, + context: SqlBlockFormattingContext, private val customSpacingBuilder: SqlCustomSpacingBuilder?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, -) : SqlBlock( +) : SqlExprBlock( node, - wrap, - alignment, - null, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override fun buildChildren(): MutableList = mutableListOf() 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 ebc60d5c..dbb0274f 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 @@ -15,41 +15,27 @@ */ package org.domaframework.doma.intellij.formatter.block.expr -import com.intellij.formatting.Alignment import com.intellij.formatting.Block -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Spacing -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType -import org.domaframework.doma.intellij.formatter.SqlCustomSpacingBuilder import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.SqlBlockCommentBlock -import org.domaframework.doma.intellij.formatter.block.SqlCommentBlock 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.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.SqlTypes open class SqlElBlockCommentBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, + private val context: SqlBlockFormattingContext, open val customSpacingBuilder: SqlCustomSpacingBuilder?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - private val formatMode: FormattingMode, -) : SqlCommentBlock( - node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, - ) { +) : SqlCommentBlock(node, context) { override val indent = ElementIndent( IndentType.NONE, @@ -57,8 +43,8 @@ open class SqlElBlockCommentBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.NONE indent.indentLen = createBlockIndentLen() indent.groupIndentLen = 0 @@ -82,45 +68,32 @@ open class SqlElBlockCommentBlock( SqlTypes.GE, SqlTypes.LE, SqlTypes.GT, SqlTypes.LT, SqlTypes.EL_EQ, SqlTypes.EL_NE, SqlTypes.PLUS, SqlTypes.MINUS, SqlTypes.ASTERISK, SqlTypes.SLASH, SqlTypes.AT_SIGN, -> - SqlOperationBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + SqlOperationBlock(child, context) SqlTypes.EL_FIELD_ACCESS_EXPR -> SqlElFieldAccessBlock( child, - wrap, - alignment, + context, createFieldAccessSpacingBuilder(), - spacingBuilder, - isEnableFormat(), - formatMode, ) SqlTypes.EL_STATIC_FIELD_ACCESS_EXPR -> SqlElStaticFieldAccessBlock( child, - wrap, - alignment, - createStaticFieldSpacingBuilder(), - spacingBuilder, - isEnableFormat(), - formatMode, + context, ) SqlTypes.EL_FUNCTION_CALL_EXPR -> SqlElFunctionCallBlock( child, - wrap, - alignment, + context, createSpacingBuilder(), - spacingBuilder, - isEnableFormat(), - formatMode, ) SqlTypes.BLOCK_COMMENT_CONTENT -> - SqlBlockCommentBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + SqlBlockCommentBlock(child, context) - else -> SqlUnknownBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + else -> SqlUnknownBlock(child, context) } private fun createFieldAccessSpacingBuilder(): SqlCustomSpacingBuilder = diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElClassBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElClassBlock.kt index 07f1efd8..d4660e01 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElClassBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElClassBlock.kt @@ -15,36 +15,24 @@ */ package org.domaframework.doma.intellij.formatter.block.expr -import com.intellij.formatting.Alignment import com.intellij.formatting.Block -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Spacing -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.SqlCustomSpacingBuilder import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlUnknownBlock +import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext import org.domaframework.doma.intellij.psi.SqlTypes class SqlElClassBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, + private val context: SqlBlockFormattingContext, private val customSpacingBuilder: SqlCustomSpacingBuilder?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - private val formatMode: FormattingMode, -) : SqlBlock( +) : SqlExprBlock( node, - wrap, - alignment, - customSpacingBuilder, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override fun buildChildren(): MutableList { val blocks = mutableListOf() @@ -61,11 +49,11 @@ class SqlElClassBlock( override fun getBlock(child: ASTNode): SqlBlock = when (child.elementType) { - SqlTypes.EL_IDENTIFIER -> SqlElIdentifierBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + SqlTypes.EL_IDENTIFIER -> SqlElIdentifierBlock(child, context) - SqlTypes.DOT -> SqlElDotBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + SqlTypes.DOT -> SqlElDotBlock(child, context) - else -> SqlUnknownBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + else -> SqlUnknownBlock(child, context) } override fun getSpacing( diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElClassRightBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElClassRightBlock.kt index a2fbc639..a27d727a 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElClassRightBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElClassRightBlock.kt @@ -15,31 +15,18 @@ */ package org.domaframework.doma.intellij.formatter.block.expr -import com.intellij.formatting.Alignment import com.intellij.formatting.Block -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Spacing -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext class SqlElClassRightBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, -) : SqlBlock( + context: SqlBlockFormattingContext, +) : SqlExprBlock( node, - wrap, - alignment, - null, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override fun buildChildren(): MutableList = mutableListOf() diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElCommaBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElCommaBlock.kt index c8b71e6d..3b79ee3e 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElCommaBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElCommaBlock.kt @@ -15,27 +15,16 @@ */ package org.domaframework.doma.intellij.formatter.block.expr -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -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.util.SqlBlockFormattingContext open class SqlElCommaBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, -) : SqlElSymbolBlock( + context: SqlBlockFormattingContext, +) : SqlExprBlock( node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override fun buildChildren(): MutableList = mutableListOf() } 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 9d9d4b81..2747d486 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 @@ -15,30 +15,27 @@ */ package org.domaframework.doma.intellij.formatter.block.expr -import com.intellij.formatting.Alignment import com.intellij.formatting.Block -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Spacing -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.formatter.common.AbstractBlock import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.elementType import org.domaframework.doma.intellij.extension.expr.isConditionOrLoopDirective -import org.domaframework.doma.intellij.formatter.IndentType -import org.domaframework.doma.intellij.formatter.SqlCustomSpacingBuilder import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.SqlBlockCommentBlock import org.domaframework.doma.intellij.formatter.block.SqlCommaBlock import org.domaframework.doma.intellij.formatter.block.SqlOperationBlock import org.domaframework.doma.intellij.formatter.block.SqlUnknownBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlCreateKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInsertKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnGroupBlock +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.SqlColumnRawGroupBlock 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 import org.domaframework.doma.intellij.psi.SqlElIfDirective @@ -46,20 +43,12 @@ import org.domaframework.doma.intellij.psi.SqlTypes class SqlElConditionLoopCommentBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, + private val context: SqlBlockFormattingContext, override val customSpacingBuilder: SqlCustomSpacingBuilder?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - private val formatMode: FormattingMode, ) : SqlElBlockCommentBlock( node, - wrap, - alignment, + context, customSpacingBuilder, - spacingBuilder, - enableFormat, - formatMode, ) { enum class SqlConditionLoopCommentBlockType { CONDITION, @@ -100,8 +89,8 @@ class SqlElConditionLoopCommentBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.NONE indent.indentLen = createBlockIndentLen() indent.groupIndentLen = 0 @@ -125,45 +114,32 @@ class SqlElConditionLoopCommentBlock( SqlTypes.GE, SqlTypes.LE, SqlTypes.GT, SqlTypes.LT, SqlTypes.EL_EQ, SqlTypes.EL_NE, SqlTypes.PLUS, SqlTypes.MINUS, SqlTypes.ASTERISK, SqlTypes.SLASH, SqlTypes.AT_SIGN, -> - SqlOperationBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + SqlOperationBlock(child, context) SqlTypes.EL_FIELD_ACCESS_EXPR -> SqlElFieldAccessBlock( child, - wrap, - alignment, + context, createFieldAccessSpacingBuilder(), - spacingBuilder, - isEnableFormat(), - formatMode, ) SqlTypes.EL_STATIC_FIELD_ACCESS_EXPR -> SqlElStaticFieldAccessBlock( child, - wrap, - alignment, - createStaticFieldSpacingBuilder(), - spacingBuilder, - isEnableFormat(), - formatMode, + context, ) SqlTypes.EL_FUNCTION_CALL_EXPR -> SqlElFunctionCallBlock( child, - wrap, - alignment, + context, createSpacingBuilder(), - spacingBuilder, - isEnableFormat(), - formatMode, ) SqlTypes.BLOCK_COMMENT_CONTENT -> - SqlBlockCommentBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + SqlBlockCommentBlock(child, context) - else -> SqlUnknownBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + else -> SqlUnknownBlock(child, context) } private fun createFieldAccessSpacingBuilder(): SqlCustomSpacingBuilder = @@ -229,10 +205,10 @@ class SqlElConditionLoopCommentBlock( val grandIndentLen = grand.indent.groupIndentLen return grandIndentLen.plus(parentGroupIndentLen).minus(1) } - if (grand is SqlInsertKeywordGroupBlock) { + if (grand is SqlInsertQueryGroupBlock) { return parentGroupIndentLen } - if (grand is SqlColumnGroupBlock) { + if (grand is SqlColumnRawGroupBlock) { val grandIndentLen = grand.indent.groupIndentLen var prevTextLen = 1 parent.prevChildren?.dropLast(1)?.forEach { prev -> diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElDotBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElDotBlock.kt index 6f49dd8b..25d4f928 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElDotBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElDotBlock.kt @@ -15,29 +15,18 @@ */ package org.domaframework.doma.intellij.formatter.block.expr -import com.intellij.formatting.Alignment import com.intellij.formatting.Block -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Spacing -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.util.SqlBlockFormattingContext open class SqlElDotBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, -) : SqlElSymbolBlock( + context: SqlBlockFormattingContext, +) : SqlExprBlock( node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override fun buildChildren(): MutableList = mutableListOf() diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElFieldAccessBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElFieldAccessBlock.kt index a630c054..df3c40b6 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElFieldAccessBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElFieldAccessBlock.kt @@ -15,35 +15,23 @@ */ package org.domaframework.doma.intellij.formatter.block.expr -import com.intellij.formatting.Alignment import com.intellij.formatting.Block -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Spacing -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.SqlCustomSpacingBuilder import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext import org.domaframework.doma.intellij.psi.SqlTypes class SqlElFieldAccessBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, + private val context: SqlBlockFormattingContext, private val customSpacingBuilder: SqlCustomSpacingBuilder?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - private val formatMode: FormattingMode, -) : SqlBlock( +) : SqlExprBlock( node, - wrap, - alignment, - customSpacingBuilder, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override fun buildChildren(): MutableList { val blocks = mutableListOf() @@ -61,19 +49,28 @@ class SqlElFieldAccessBlock( override fun getBlock(child: ASTNode): SqlBlock = when (child.elementType) { SqlTypes.EL_PRIMARY_EXPR -> { - SqlElPrimaryBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + SqlElPrimaryBlock(child, context) } SqlTypes.DOT -> - SqlElDotBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + SqlElDotBlock(child, context) SqlTypes.EL_IDENTIFIER -> - SqlElIdentifierBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + SqlElIdentifierBlock(child, context) SqlTypes.EL_PARAMETERS -> - SqlElParametersBlock(child, wrap, alignment, customSpacingBuilder, spacingBuilder, isEnableFormat(), formatMode) + SqlElParametersBlock(child, context, customSpacingBuilder) - else -> SqlBlock(child, wrap, alignment, customSpacingBuilder, spacingBuilder, isEnableFormat(), formatMode) + else -> + SqlBlock( + child, + context.wrap, + context.alignment, + customSpacingBuilder, + context.spacingBuilder, + context.enableFormat, + context.formatMode, + ) } override fun getSpacing( diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElFunctionCallBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElFunctionCallBlock.kt index 43b78a5c..9f6e9bde 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElFunctionCallBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElFunctionCallBlock.kt @@ -15,33 +15,21 @@ */ package org.domaframework.doma.intellij.formatter.block.expr -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.SqlCustomSpacingBuilder import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext import org.domaframework.doma.intellij.psi.SqlTypes class SqlElFunctionCallBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, + private val context: SqlBlockFormattingContext, customSpacingBuilder: SqlCustomSpacingBuilder?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - private val formatMode: FormattingMode, -) : SqlBlock( +) : SqlExprBlock( node, - wrap, - alignment, - customSpacingBuilder, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override fun buildChildren(): MutableList { val blocks = mutableListOf() @@ -59,15 +47,24 @@ class SqlElFunctionCallBlock( override fun getBlock(child: ASTNode): SqlBlock = when (child.elementType) { SqlTypes.AT_SIGN -> - SqlElAtSignBlock(child, wrap, alignment, createSpacingBuilder(), spacingBuilder, isEnableFormat(), formatMode) + SqlElAtSignBlock(child, context, createSpacingBuilder()) SqlTypes.EL_IDENTIFIER -> - SqlElIdentifierBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + SqlElIdentifierBlock(child, context) SqlTypes.EL_PARAMETERS -> - SqlElParametersBlock(child, wrap, alignment, createSpacingBuilder(), spacingBuilder, isEnableFormat(), formatMode) + SqlElParametersBlock(child, context, createSpacingBuilder()) - else -> SqlBlock(child, wrap, alignment, createSpacingBuilder(), spacingBuilder, isEnableFormat(), formatMode) + else -> + SqlBlock( + child, + wrap, + alignment, + createSpacingBuilder(), + spacingBuilder, + context.enableFormat, + context.formatMode, + ) } override fun isLeaf(): Boolean = false diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElIdentifierBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElIdentifierBlock.kt index f61f5845..86d41cb8 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElIdentifierBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElIdentifierBlock.kt @@ -15,29 +15,16 @@ */ package org.domaframework.doma.intellij.formatter.block.expr -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext class SqlElIdentifierBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, -) : SqlBlock( + context: SqlBlockFormattingContext, +) : SqlExprBlock( node, - wrap, - alignment, - null, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override fun buildChildren(): MutableList = mutableListOf() diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElParametersBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElParametersBlock.kt index 3c58861d..0d2b66f6 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElParametersBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElParametersBlock.kt @@ -15,45 +15,33 @@ */ package org.domaframework.doma.intellij.formatter.block.expr -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode -import org.domaframework.doma.intellij.formatter.SqlCustomSpacingBuilder import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlUnknownBlock +import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext import org.domaframework.doma.intellij.psi.SqlTypes class SqlElParametersBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, + private val context: SqlBlockFormattingContext, customSpacingBuilder: SqlCustomSpacingBuilder?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - private val formatMode: FormattingMode, -) : SqlBlock( +) : SqlExprBlock( node, - wrap, - alignment, - customSpacingBuilder, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override fun getBlock(child: ASTNode): SqlBlock = when (child.elementType) { SqlTypes.LEFT_PAREN, SqlTypes.RIGHT_PAREN -> - SqlElSymbolBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + SqlElSymbolBlock(child, context) SqlTypes.EL_PRIMARY_EXPR -> - SqlElPrimaryBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + SqlElPrimaryBlock(child, context) SqlTypes.COMMA -> - SqlElCommaBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + SqlElCommaBlock(child, context) - else -> SqlUnknownBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + else -> SqlUnknownBlock(child, context) } override fun isLeaf(): Boolean = false diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElPrimaryBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElPrimaryBlock.kt index 1d5e84b3..16b81e10 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElPrimaryBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElPrimaryBlock.kt @@ -15,30 +15,17 @@ */ package org.domaframework.doma.intellij.formatter.block.expr -import com.intellij.formatting.Alignment import com.intellij.formatting.Block -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Spacing -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode -import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext class SqlElPrimaryBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, -) : SqlBlock( + context: SqlBlockFormattingContext, +) : SqlExprBlock( node, - wrap, - alignment, - null, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override fun getSpacing( child1: Block?, diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElStaticFieldAccessBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElStaticFieldAccessBlock.kt index bf9bf98e..b8efbe12 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElStaticFieldAccessBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElStaticFieldAccessBlock.kt @@ -15,36 +15,23 @@ */ package org.domaframework.doma.intellij.formatter.block.expr -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Spacing -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.util.PsiTreeUtil -import org.domaframework.doma.intellij.formatter.SqlCustomSpacingBuilder import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.SqlUnknownBlock +import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext import org.domaframework.doma.intellij.psi.SqlElClass import org.domaframework.doma.intellij.psi.SqlTypes class SqlElStaticFieldAccessBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - customSpacingBuilder: SqlCustomSpacingBuilder?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - private val formatMode: FormattingMode, -) : SqlBlock( + private val context: SqlBlockFormattingContext, +) : SqlExprBlock( node, - wrap, - alignment, - customSpacingBuilder, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override fun getBlock(child: ASTNode): SqlBlock = when (child.elementType) { @@ -54,19 +41,19 @@ class SqlElStaticFieldAccessBlock( PsiWhiteSpace::class.java, ) is SqlElClass ) { - SqlElClassRightBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + SqlElClassRightBlock(child, context) } else { - SqlElAtSignBlock(child, wrap, alignment, null, spacingBuilder, isEnableFormat(), formatMode) + SqlElAtSignBlock(child, context, null) } } SqlTypes.EL_CLASS -> - SqlElClassBlock(child, wrap, alignment, null, spacingBuilder, isEnableFormat(), formatMode) + SqlElClassBlock(child, context, null) SqlTypes.EL_IDENTIFIER -> - SqlElIdentifierBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + SqlElIdentifierBlock(child, context) - else -> SqlUnknownBlock(child, wrap, alignment, spacingBuilder, isEnableFormat(), formatMode) + else -> SqlUnknownBlock(child, context) } override fun createSpacingBuilder(): SqlCustomSpacingBuilder = diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElSymbolBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElSymbolBlock.kt index 2e3cc8a1..cb9f7052 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElSymbolBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlElSymbolBlock.kt @@ -15,30 +15,18 @@ */ package org.domaframework.doma.intellij.formatter.block.expr -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext open class SqlElSymbolBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, -) : SqlBlock( + context: SqlBlockFormattingContext, +) : SqlExprBlock( node, - wrap, - alignment, - null, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override val indent = ElementIndent( @@ -47,8 +35,8 @@ open class SqlElSymbolBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.NONE indent.indentLen = 0 indent.groupIndentLen = 0 diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlExprBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlExprBlock.kt new file mode 100644 index 00000000..e7768c50 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/expr/SqlExprBlock.kt @@ -0,0 +1,40 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.expr + +import com.intellij.formatting.Block +import com.intellij.formatting.Spacing +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext + +abstract class SqlExprBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlBlock( + node, + context.wrap, + context.alignment, + null, + context.spacingBuilder, + context.enableFormat, + context.formatMode, + ) { + override fun getSpacing( + p0: Block?, + p1: Block, + ): Spacing? = null +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlColumnDefinitionRawGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlColumnDefinitionRawGroupBlock.kt index 745c72f7..4b005a41 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlColumnDefinitionRawGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlColumnDefinitionRawGroupBlock.kt @@ -13,46 +13,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block.group +package org.domaframework.doma.intellij.formatter.block.group.column -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnDefinitionGroupBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext import org.domaframework.doma.intellij.psi.SqlTypes /** * Column definition group block in the column list group attached to Create Table - * The parent must be SqlColumnDefinitionGroupBlock + * The parent must be SqlCreateTableColumnDefinitionGroupBlock */ -class SqlColumnDefinitionRawGroupBlock( +open class SqlColumnDefinitionRawGroupBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, -) : SqlBlock( + context: SqlBlockFormattingContext, +) : SqlRawGroupBlock( node, - wrap, - alignment, - null, - spacingBuilder, - enableFormat, - formatMode, + context, ) { // TODO:Customize indentation within an inline group val defaultOffset = 5 val isFirstColumnRaw = node.elementType != SqlTypes.COMMA - var columnName = getNodeText() + open var columnBlock: SqlBlock? = if (isFirstColumnRaw) this else null - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLen = createBlockIndentLen() indent.groupIndentLen = indent.indentLen } @@ -62,27 +49,5 @@ class SqlColumnDefinitionRawGroupBlock( /** * Right-justify the longest column name in the column definition. */ - override fun createBlockIndentLen(): Int { - if (!isFirstColumnRaw) return defaultOffset - - parentBlock?.let { - return when (it) { - is SqlColumnDefinitionGroupBlock -> { - getColumnRawNewIndent(it) - } - - else -> { - 1 - } - } - } - return 1 - } - - private fun getColumnRawNewIndent(groupRawBlock: SqlColumnDefinitionGroupBlock): Int { - val groupMaxAlimentLen = groupRawBlock.alignmentColumnName.length - val diffColumnName = groupMaxAlimentLen.minus(columnName.length) - val newSpaces = defaultOffset.plus(diffColumnName) - return newSpaces.plus(2) - } + override fun createBlockIndentLen(): Int = if (isFirstColumnRaw) 1 else defaultOffset } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlNewGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlNewGroupBlock.kt index 713207e9..32eaf2b9 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlNewGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/SqlNewGroupBlock.kt @@ -15,26 +15,35 @@ */ package org.domaframework.doma.intellij.formatter.block.group -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext +import org.domaframework.doma.intellij.psi.SqlTypes abstract class SqlNewGroupBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlBlock( node, - wrap, - alignment, + context.wrap, + context.alignment, null, - spacingBuilder, - enableFormat, - formatMode, - ) + context.spacingBuilder, + context.enableFormat, + context.formatMode, + ) { + protected fun getKeywordNameLength( + blocks: List, + dropLast: Int = 0, + ): Int { + val keywords = + blocks + .dropLast(dropLast) + .takeWhile { it.node.elementType == SqlTypes.KEYWORD } + val parentLen = + keywords.sumOf { keyword -> + keyword.getNodeText().length.plus(1) + } + return parentLen + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/column/SqlRawGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/column/SqlRawGroupBlock.kt new file mode 100644 index 00000000..430a41be --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/column/SqlRawGroupBlock.kt @@ -0,0 +1,53 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.column + +import com.intellij.formatting.Block +import com.intellij.formatting.Spacing +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.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext + +abstract class SqlRawGroupBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlBlock( + node, + context.wrap, + context.alignment, + null, + context.spacingBuilder, + context.enableFormat, + context.formatMode, + ) { + override val indent = + ElementIndent( + IndentType.COLUMN, + 0, + 0, + ) + + override fun getSpacing( + p0: Block?, + p1: Block, + ): Spacing? = null + + override fun buildChildren(): MutableList = mutableListOf() + + override fun isLeaf(): Boolean = true +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/function/SqlFunctionGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/function/SqlFunctionGroupBlock.kt new file mode 100644 index 00000000..29cc54a8 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/function/SqlFunctionGroupBlock.kt @@ -0,0 +1,37 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.function + +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext + +/** + * Function call group + * + * For Example: + * -- FUNC is [SqlFunctionGroupBlock] + * SELECT FUNC(index -- "(" that after FUNC is [SqlParamGroupBlock] + * , (SELECT number -- "index" and "," is [SqlParamBlock] + * FROM demo) + * , (num1 + num2)) + */ +class SqlFunctionGroupBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlSubGroupBlock(node, context) { + val parameterGroupBlock: SqlParamGroupBlock? = null +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/function/SqlParamBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/function/SqlParamBlock.kt new file mode 100644 index 00000000..b44f5f37 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/function/SqlParamBlock.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.group.function + +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext +import org.domaframework.doma.intellij.psi.SqlTypes + +/** + * Parameter block of the function call + */ +class SqlParamBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlBlock( + node, + context.wrap, + context.alignment, + null, + context.spacingBuilder, + context.enableFormat, + context.formatMode, + ) { + val isFirstParam = node.elementType != SqlTypes.COMMA + override var parentBlock: SqlBlock? + get() = super.parentBlock as? SqlParamGroupBlock + set(value) { + if (value is SqlParamGroupBlock) { + super.parentBlock = value + } + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/function/SqlParamGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/function/SqlParamGroupBlock.kt new file mode 100644 index 00000000..679aff38 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/function/SqlParamGroupBlock.kt @@ -0,0 +1,32 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.function + +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext + +/** + * Group block for parameters in a function call. + */ +class SqlParamGroupBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlSubGroupBlock(node, context) { + // Contains a SqlSubGroupBlock or SqlParamBlock + val paramGroupBlock: MutableList = mutableListOf() +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInlineGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInlineGroupBlock.kt index 524c860b..aea65d2e 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInlineGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInlineGroupBlock.kt @@ -15,31 +15,20 @@ */ package org.domaframework.doma.intellij.formatter.block.group.keyword -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Indent -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock 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 open class SqlInlineGroupBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlNewGroupBlock( node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override val indent = ElementIndent( @@ -48,8 +37,8 @@ open class SqlInlineGroupBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.INLINE indent.indentLen = createBlockIndentLen() indent.groupIndentLen = indent.indentLen.plus(getNodeText().length) diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInlineSecondGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInlineSecondGroupBlock.kt index 6e9df359..237c5353 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInlineSecondGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInlineSecondGroupBlock.kt @@ -15,31 +15,20 @@ */ package org.domaframework.doma.intellij.formatter.block.group.keyword -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Indent -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock 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 open class SqlInlineSecondGroupBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlNewGroupBlock( node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { val isEndCase = getNodeText().lowercase() == "end" @@ -50,8 +39,8 @@ open class SqlInlineSecondGroupBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.INLINE_SECOND indent.indentLen = createBlockIndentLen() indent.groupIndentLen = indent.indentLen 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 7fbfa4d8..96171766 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 @@ -15,31 +15,20 @@ */ package org.domaframework.doma.intellij.formatter.block.group.keyword -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Indent -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext open class SqlJoinGroupBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlKeywordGroupBlock( node, IndentType.JOIN, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override val indent = ElementIndent( @@ -48,11 +37,11 @@ open class SqlJoinGroupBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - parentBlock = block + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + parentBlock = lastGroup parentBlock?.childBlocks?.add(this) indent.indentLevel = IndentType.JOIN - indent.indentLen = createBlockIndentLen() + indent.indentLen = createBlockIndentLen(null) indent.groupIndentLen = indent.indentLen.plus(getNodeText().length) } @@ -65,7 +54,7 @@ open class SqlJoinGroupBlock( Indent.getSpaceIndent(indent.indentLen) } - override fun createBlockIndentLen(): Int = + override fun createBlockIndentLen(preChildBlock: SqlBlock?): Int = parentBlock ?.indent ?.groupIndentLen 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 432b59aa..18b3458a 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 @@ -15,38 +15,24 @@ */ package org.domaframework.doma.intellij.formatter.block.group.keyword -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Indent -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType -import org.domaframework.doma.intellij.formatter.SqlKeywordUtil import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateViewGroupBlock +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.block.group.subgroup.SqlSubQueryGroupBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlViewGroupBlock -import org.domaframework.doma.intellij.psi.SqlTypes +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext +import org.domaframework.doma.intellij.formatter.util.SqlKeywordUtil open class SqlKeywordGroupBlock( node: ASTNode, val indentLevel: IndentType = IndentType.TOP, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, -) : SqlNewGroupBlock( - node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, - ) { + context: SqlBlockFormattingContext, +) : SqlNewGroupBlock(node, context) { override val indent = ElementIndent( indentLevel, @@ -54,27 +40,40 @@ open class SqlKeywordGroupBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) - val preChildBlock = block?.childBlocks?.dropLast(1)?.lastOrNull() + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) + val preChildBlock = lastGroup?.childBlocks?.dropLast(1)?.lastOrNull() indent.indentLevel = indentLevel - val baseIndentLen = getBaseIndentLen(preChildBlock, block) + val baseIndentLen = getBaseIndentLen(preChildBlock, lastGroup) indent.groupIndentLen = baseIndentLen.plus(getNodeText().length) indent.indentLen = adjustIndentIfFirstChildIsLineComment(baseIndentLen) createGroupIndentLen() } - private fun getBaseIndentLen( + override fun setParentPropertyBlock(lastGroup: SqlBlock?) { + if (lastGroup is SqlSelectKeywordGroupBlock && + SqlKeywordUtil.isSelectSecondOptionKeyword(getNodeText()) + ) { + lastGroup.secondGroupBlocks.add(this) + } + + if (getNodeText() == "values" && lastGroup is SqlInsertQueryGroupBlock) { + lastGroup.valueKeywordBlock = this + } + } + + open fun getBaseIndentLen( preChildBlock: SqlBlock?, block: SqlBlock?, ): Int { if (block == null) { - return createBlockIndentLen() + return createBlockIndentLen(preChildBlock) } - if (preChildBlock != null && - preChildBlock.indent.indentLevel == this.indent.indentLevel && - !SqlKeywordUtil.isSetLineKeyword(preChildBlock.getNodeText(), block.getNodeText()) + if (preChildBlock == null) return createBlockIndentLen(preChildBlock) + + if (preChildBlock.indent.indentLevel == this.indent.indentLevel && + !SqlKeywordUtil.isSetLineKeyword(getNodeText(), preChildBlock.getNodeText()) ) { if (indent.indentLevel == IndentType.SECOND) { val diffPreBlockTextLen = getNodeText().length.minus(preChildBlock.getNodeText().length) @@ -84,7 +83,7 @@ open class SqlKeywordGroupBlock( return preChildBlock.indent.indentLen.minus(diffPretextLen) } } else { - return createBlockIndentLen() + return createBlockIndentLen(preChildBlock) } } @@ -100,12 +99,12 @@ open class SqlKeywordGroupBlock( /** * Adjust the indent position of the subgroup block element itself if it has a comment */ - private fun adjustIndentIfFirstChildIsLineComment(baseIndent: Int): Int { - parentBlock?.let { + open fun adjustIndentIfFirstChildIsLineComment(baseIndent: Int): Int { + parentBlock?.let { parent -> if (indent.indentLevel == IndentType.TOP) { - return if (it is SqlSubGroupBlock) { - return if (it.isFirstLineComment) { - it.indent.groupIndentLen.minus(it.getNodeText().length) + 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 @@ -118,11 +117,16 @@ open class SqlKeywordGroupBlock( return baseIndent } - override fun createBlockIndentLen(): Int { + open fun createBlockIndentLen(preChildBlock: SqlBlock?): Int { when (indentLevel) { IndentType.TOP -> { parentBlock?.let { val groupLen = it.indent.groupIndentLen + if (SqlKeywordUtil.isSetLineKeyword(getNodeText(), preChildBlock?.getNodeText() ?: "")) { + val prevBlockIndent = preChildBlock?.indent?.indentLen ?: 0 + val prevBlockLen = preChildBlock?.getNodeText()?.length ?: 0 + return prevBlockIndent.plus(prevBlockLen).plus(1) + } return if (it.indent.indentLevel == IndentType.FILE) { 0 } else { @@ -139,7 +143,7 @@ open class SqlKeywordGroupBlock( return 0 } else { parent.parentBlock?.let { grand -> - return if (grand is SqlViewGroupBlock) { + return if (grand is SqlCreateViewGroupBlock) { groupLen.minus(this.getNodeText().length) } else if (grand is SqlSubGroupBlock) { groupLen.minus(getNodeText().length).plus(1) @@ -170,18 +174,12 @@ open class SqlKeywordGroupBlock( } else if (parent is SqlKeywordGroupBlock && subGroupBlock != null && subGroupBlock.isFirstLineComment) { groupLen } else { - var parentLen = 0 val removeStartOffsetLess = parent.childBlocks.dropLast(1).filter { it.node.startOffset > parent.node.startOffset } - val keywords = - removeStartOffsetLess - .takeWhile { it.node.elementType == SqlTypes.KEYWORD } - keywords.forEach { keyword -> - parentLen = parentLen.plus(keyword.getNodeText().length).plus(1) - } + val parentLen = getKeywordNameLength(removeStartOffsetLess, 0) val parentTextLen = parent.indent.groupIndentLen.plus(parentLen) return parentTextLen.minus(getNodeText().length) } @@ -202,15 +200,11 @@ open class SqlKeywordGroupBlock( return 1 } - private fun createGroupIndentLen(): Int { - parentBlock?.let { + protected open fun createGroupIndentLen(): Int { + parentBlock?.let { parent -> if (indent.indentLevel == IndentType.SECOND_OPTION) { - var parentLen = 0 - val keywords = it.childBlocks.dropLast(1).filter { it.node.elementType == SqlTypes.KEYWORD } - keywords.forEach { keyword -> - parentLen = parentLen.plus(keyword.getNodeText().length).plus(1) - } - it.indent.groupIndentLen + val parentLen = getKeywordNameLength(parent.childBlocks, 1) + parent.indent.groupIndentLen .plus(parentLen) .minus(getNodeText().length) } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlSelectKeywordGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlSelectKeywordGroupBlock.kt new file mode 100644 index 00000000..53adbe2e --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlSelectKeywordGroupBlock.kt @@ -0,0 +1,61 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.keyword + +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext + +class SqlSelectKeywordGroupBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlKeywordGroupBlock(node, IndentType.TOP, context) { + val secondGroupBlocks: MutableList = mutableListOf() + val selectionColumns: MutableList = mutableListOf() + + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) + val preChildBlock = lastGroup?.childBlocks?.dropLast(1)?.lastOrNull() + indent.indentLevel = indentLevel + + val baseIndentLen = getBaseIndentLen(preChildBlock, lastGroup) + indent.groupIndentLen = baseIndentLen.plus(getNodeText().length) + indent.indentLen = adjustIndentIfFirstChildIsLineComment(baseIndentLen) + createGroupIndentLen() + } + + override fun getBaseIndentLen( + preChildBlock: SqlBlock?, + block: SqlBlock?, + ): Int { + if (parentBlock is SqlSubGroupBlock) { + return parentBlock?.indent?.groupIndentLen + ?: createBlockIndentLen(preChildBlock) + } + return createBlockIndentLen(preChildBlock) + } + + override fun createBlockIndentLen(preChildBlock: SqlBlock?): Int = + if (parentBlock?.indent?.indentLevel == IndentType.FILE) { + 0 + } else { + parentBlock?.indent?.groupIndentLen ?: 0 + } + + override fun createGroupIndentLen(): Int = 0 +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlUpdateKeywordGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlUpdateKeywordGroupBlock.kt index a96d7b77..a7be2d14 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlUpdateKeywordGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlUpdateKeywordGroupBlock.kt @@ -15,31 +15,20 @@ */ package org.domaframework.doma.intellij.formatter.block.group.keyword -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Indent -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext open class SqlUpdateKeywordGroupBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlKeywordGroupBlock( node, IndentType.SECOND, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override fun setParentGroupBlock(block: SqlBlock?) { super.setParentGroupBlock(block) diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlWhereGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlWhereGroupBlock.kt new file mode 100644 index 00000000..7900cf53 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlWhereGroupBlock.kt @@ -0,0 +1,25 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.keyword + +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext + +class SqlWhereGroupBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlKeywordGroupBlock(node, IndentType.SECOND, context) 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 new file mode 100644 index 00000000..aa07a494 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/condition/SqlConditionKeywordGroupBlock.kt @@ -0,0 +1,43 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.keyword.condition + +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext + +/** + * Keywords representing conditions such as AND or OR + */ +class SqlConditionKeywordGroupBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlKeywordGroupBlock( + node, + IndentType.SECOND_OPTION, + context, + ) { + var conditionalExpressionGroupBlock: SqlConditionalExpressionGroupBlock? = null + + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) + if (lastGroup is SqlConditionalExpressionGroupBlock) { + lastGroup.conditionKeywordGroupBlocks.add(this) + } + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/condition/SqlConditionalExpressionGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/condition/SqlConditionalExpressionGroupBlock.kt new file mode 100644 index 00000000..d84033d2 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/condition/SqlConditionalExpressionGroupBlock.kt @@ -0,0 +1,60 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.keyword.condition + +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.block.SqlBlock +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.SqlBlockFormattingContext + +/** + * A grouped conditional expression following keywords such as AND or OR + */ +class SqlConditionalExpressionGroupBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlSubGroupBlock( + node, + context, + ) { + val conditionKeywordGroupBlocks: MutableList = mutableListOf() + + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) + if (lastGroup is SqlConditionKeywordGroupBlock) { + lastGroup.conditionalExpressionGroupBlock = this + } + } + + /** + * Processing applied to the entire group when group processing ends. + * If there are AND or OR group blocks, set the indentation so that the keywords are right-aligned. + */ + override fun endGroup() { + val thisGroupIndent = indent.groupIndentLen + if (conditionKeywordGroupBlocks.isNotEmpty()) { + conditionKeywordGroupBlocks.forEach { conditionBlock -> + conditionBlock.indent.indentLen = + when (conditionBlock.getNodeText()) { + "and" -> thisGroupIndent.plus(1) + "or" -> thisGroupIndent.plus(2) + else -> conditionBlock.indent.indentLen + } + } + } + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlCreateKeywordGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/create/SqlCreateKeywordGroupBlock.kt similarity index 70% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlCreateKeywordGroupBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/create/SqlCreateKeywordGroupBlock.kt index 5f6fb5ef..4bf8bc45 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlCreateKeywordGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/create/SqlCreateKeywordGroupBlock.kt @@ -13,39 +13,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block.group.keyword +package org.domaframework.doma.intellij.formatter.block.group.keyword.create -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Indent -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.CreateQueryType -import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.SqlTableBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.util.CreateQueryType +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext open class SqlCreateKeywordGroupBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlKeywordGroupBlock( node, IndentType.TOP, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { var createType: CreateQueryType = CreateQueryType.NONE + var tableBlock: SqlTableBlock? = null - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.TOP indent.indentLen = createBlockIndentLen() indent.groupIndentLen = indent.indentLen.plus(getNodeText().length) @@ -60,7 +52,7 @@ open class SqlCreateKeywordGroupBlock( return Indent.getNoneIndent() } - override fun createBlockIndentLen(): Int = + override fun createBlockIndentLen(preChildBlock: SqlBlock?): Int = parentBlock?.let { if (it.indent.indentLevel == IndentType.SUB) { it.indent.groupIndentLen.plus(1) @@ -70,6 +62,6 @@ open class SqlCreateKeywordGroupBlock( } ?: 0 fun setCreateQueryType(nextKeyword: String) { - createType = CreateQueryType.getCreateTableType(nextKeyword) + createType = CreateQueryType.Companion.getCreateTableType(nextKeyword) } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/create/SqlCreateTableColumnDefinitionGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/create/SqlCreateTableColumnDefinitionGroupBlock.kt new file mode 100644 index 00000000..bde293a4 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/create/SqlCreateTableColumnDefinitionGroupBlock.kt @@ -0,0 +1,62 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.keyword.create + +import com.intellij.lang.ASTNode +import com.intellij.psi.formatter.common.AbstractBlock +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnDefinitionRawGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext + +/** + * Column List Group Block attached to Create Table + * example : + * ``` + * CREATE TABLE departments + * ( -- [SqlCreateTableColumnDefinitionGroupBlock] + * id INT PRIMARY KEY -- [SqlCreateTableColumnDefinitionRawGroupBlock] + * , name VARCHAR(100) -- [SqlCreateTableColumnDefinitionRawGroupBlock] + * , loc INT NOT NULL -- [SqlCreateTableColumnDefinitionRawGroupBlock] + * ) + * ``` + */ +class SqlCreateTableColumnDefinitionGroupBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlSubGroupBlock( + node, + context, + ) { + // TODO:Customize indentation + private val offset = 2 + val columnRawGroupBlocks = mutableListOf() + + fun getMaxColumnNameLength(): Int = + columnRawGroupBlocks.maxOfOrNull { raw -> + raw.columnBlock?.getNodeText()?.length ?: 0 + } ?: 0 + + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) + indent.indentLen = createBlockIndentLen() + indent.groupIndentLen = indent.indentLen + } + + override fun buildChildren(): MutableList = mutableListOf() + + override fun createBlockIndentLen(): Int = offset +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/create/SqlCreateTableColumnDefinitionRawGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/create/SqlCreateTableColumnDefinitionRawGroupBlock.kt new file mode 100644 index 00000000..5a45103c --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/create/SqlCreateTableColumnDefinitionRawGroupBlock.kt @@ -0,0 +1,82 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.keyword.create + +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnDefinitionRawGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.column.SqlDataTypeBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext +import org.domaframework.doma.intellij.psi.SqlTypes + +class SqlCreateTableColumnDefinitionRawGroupBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlColumnDefinitionRawGroupBlock( + node, + context, + ) { + var columnDataTypeBlock: SqlDataTypeBlock? = null + + override var parentBlock: SqlBlock? + get() = super.parentBlock as? SqlCreateTableColumnDefinitionGroupBlock + set(value) { + if (value is SqlCreateTableColumnDefinitionGroupBlock) { + super.parentBlock = value + } + } + + override var columnBlock: SqlBlock? + get() = super.columnBlock + set(value) { + if (value?.node?.elementType == SqlTypes.COMMA) { + super.columnBlock = null + } else { + super.columnBlock = value + } + } + + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) + indent.indentLen = createBlockIndentLen() + indent.groupIndentLen = indent.indentLen + } + + override fun setParentPropertyBlock(lastGroup: SqlBlock?) { + (lastGroup as? SqlCreateTableColumnDefinitionGroupBlock) + ?.columnRawGroupBlocks + ?.add( + this, + ) + } + + override fun createBlockIndentLen(): Int = + (parentBlock as? SqlCreateTableColumnDefinitionGroupBlock) + ?.let { parent -> + return getColumnRawNewIndent(parent) + } ?: 1 + + /** + * Aligns each column name to the right based on the longest column name + * within the column definition group of a Create Table query. + */ + private fun getColumnRawNewIndent(groupRawBlock: SqlCreateTableColumnDefinitionGroupBlock): Int { + val groupMaxAlimentLen = groupRawBlock.getMaxColumnNameLength() + val diffColumnName = groupMaxAlimentLen.minus(getNodeText().length) + val newSpaces = defaultOffset.plus(diffColumnName) + return newSpaces.plus(2) + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlViewGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/create/SqlCreateViewGroupBlock.kt similarity index 67% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlViewGroupBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/create/SqlCreateViewGroupBlock.kt index c22ecd6d..8a6372dd 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlViewGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/create/SqlCreateViewGroupBlock.kt @@ -13,34 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block.group.subgroup +package org.domaframework.doma.intellij.formatter.block.group.keyword.create -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Indent -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext -open class SqlViewGroupBlock( +open class SqlCreateViewGroupBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlKeywordGroupBlock( node, IndentType.SECOND, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override val indent = ElementIndent( @@ -49,8 +38,8 @@ open class SqlViewGroupBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.SUB indent.indentLen = createBlockIndentLen() indent.groupIndentLen = getNodeText().length @@ -65,7 +54,7 @@ open class SqlViewGroupBlock( Indent.getSpaceIndent(indent.indentLen) } - override fun createBlockIndentLen(): Int = parentBlock?.indent?.indentLen ?: 0 + override fun createBlockIndentLen(preChildBlock: SqlBlock?): Int = parentBlock?.indent?.indentLen ?: 0 override fun isLeaf(): Boolean = true } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/insert/SqlInsertColumnGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/insert/SqlInsertColumnGroupBlock.kt new file mode 100644 index 00000000..fc92a5ec --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/insert/SqlInsertColumnGroupBlock.kt @@ -0,0 +1,96 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.keyword.insert + +import com.intellij.lang.ASTNode +import com.intellij.psi.formatter.common.AbstractBlock +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext + +/** + * Block of columns to insert + * For Example: + * INSERT INTO users + * (username -- [SqlInsertColumnGroupBlock] + * , email) + * VALUES ('user' + * , 'user@example.com') + */ +class SqlInsertColumnGroupBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlSubGroupBlock( + node, + context, + ) { + // TODO:Customize indentation + private val offset = 2 + + /** + * A list of row blocks representing the target columns in an `INSERT` statement, + * distinct from the column line group. + * This list may include: + * **Column row blocks** + * **Subgroup blocks** + * **Conditional or rule directives** + */ + val columnRaws: MutableList = mutableListOf() + + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) + indent.indentLen = createBlockIndentLen() + indent.groupIndentLen = indent.indentLen.plus(1) + updateParentGroupIndentLen() + } + + override fun setParentPropertyBlock(lastGroup: SqlBlock?) { + (lastGroup as? SqlInsertQueryGroupBlock)?.columnDefinitionGroupBlock = this + } + + override fun buildChildren(): MutableList = mutableListOf() + + /** + * Set the column line indentation to match the length of the `INSERT` query keyword (including `INSERT INTO`). + */ + override fun createBlockIndentLen(): Int { + parentBlock?.let { parent -> + val parentBaseLen = getParentInsertKeywordsIndentLength(parent) + return parentBaseLen.plus(1) + } ?: return offset + } + + /** + * Retrieve the length of the INSERT query keyword (including INSERT INTO) + * and adjust the indentation baseline for the INSERT group accordingly. + */ + private fun updateParentGroupIndentLen() { + parentBlock?.let { parent -> + val parentBaseLen = getParentInsertKeywordsIndentLength(parent) + parent.indent.groupIndentLen = parentBaseLen + } + } + + private fun getParentInsertKeywordsIndentLength(parent: SqlBlock): Int { + if (parent is SqlInsertQueryGroupBlock) { + var parentLen = getKeywordNameLength(parent.childBlocks, 1) + return parentLen + .plus(parent.indent.indentLen) + .plus(parent.getNodeText().length) + } + return parent.indent.groupIndentLen + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInsertKeywordGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/insert/SqlInsertQueryGroupBlock.kt similarity index 67% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInsertKeywordGroupBlock.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/insert/SqlInsertQueryGroupBlock.kt index 3aafafea..a688c10a 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlInsertKeywordGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/insert/SqlInsertQueryGroupBlock.kt @@ -13,36 +13,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter.block.group.keyword +package org.domaframework.doma.intellij.formatter.block.group.keyword.insert -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode import com.intellij.formatting.Indent -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock +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 +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext -open class SqlInsertKeywordGroupBlock( +open class SqlInsertQueryGroupBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlKeywordGroupBlock( node, IndentType.TOP, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + var columnDefinitionGroupBlock: SqlInsertColumnGroupBlock? = null + var valueKeywordBlock: SqlKeywordGroupBlock? = null + var valueGroupBlock: SqlSubGroupBlock? = null + + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.TOP indent.indentLen = createBlockIndentLen() indent.groupIndentLen = indent.indentLen.plus(getNodeText().length) @@ -52,7 +47,7 @@ open class SqlInsertKeywordGroupBlock( override fun getIndent(): Indent? = Indent.getSpaceIndent(indent.indentLen) - override fun createBlockIndentLen(): Int = + override fun createBlockIndentLen(preChildBlock: SqlBlock?): Int = if (!isAdjustIndentOnEnter()) { parentBlock?.let { if (it.indent.indentLevel == IndentType.SUB) { 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 new file mode 100644 index 00000000..dac5586c --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlSelectQueryGroupBlock.kt @@ -0,0 +1,27 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.keyword.top + +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext + +class SqlSelectQueryGroupBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlTopQueryGroupBlock( + node, + context, + ) 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 new file mode 100644 index 00000000..9968e8d1 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlTopQueryGroupBlock.kt @@ -0,0 +1,30 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.keyword.top + +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext + +abstract class SqlTopQueryGroupBlock( + private val node: ASTNode, + private val context: SqlBlockFormattingContext, +) : SqlKeywordGroupBlock( + node, + IndentType.TOP, + context, + ) diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/update/SqlUpdateColumnAssignmentSymbolBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/update/SqlUpdateColumnAssignmentSymbolBlock.kt new file mode 100644 index 00000000..2b29eaf6 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/update/SqlUpdateColumnAssignmentSymbolBlock.kt @@ -0,0 +1,48 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.keyword.update + +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.SqlOtherBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext + +/** + * A block representing the `=` that connects column groups and value groups in a bulk update statement. + */ +class SqlUpdateColumnAssignmentSymbolBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlOtherBlock(node, context) { + override val isNeedWhiteSpace: Boolean = true + + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) + indent.indentLen = createIndentLen() + indent.groupIndentLen = indent.groupIndentLen.plus(1) + } + + override fun setParentPropertyBlock(lastGroup: SqlBlock?) { + if (lastGroup is SqlUpdateSetGroupBlock && lastGroup.columnDefinitionGroupBlock != null) { + lastGroup.assignmentSymbol = this + } + } + + private fun createIndentLen(): Int { + parentBlock?.let { parent -> return parent.indent.groupIndentLen.plus(1) } + ?: return 0 + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/update/SqlUpdateColumnGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/update/SqlUpdateColumnGroupBlock.kt new file mode 100644 index 00000000..a55f9a1d --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/update/SqlUpdateColumnGroupBlock.kt @@ -0,0 +1,74 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.keyword.update + +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnRawGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnSelectionGroupBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext + +/** + * In an UPDATE statement using the row value constructor, + * a group representing the column list + */ +class SqlUpdateColumnGroupBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlColumnSelectionGroupBlock( + node, + context, + ) { + // TODO:Customize indentation + private val offset = 2 + val columnRawGroupBlocks: MutableList = mutableListOf() + + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) + indent.indentLen = createBlockIndentLen() + indent.groupIndentLen = indent.indentLen.plus(1) + updateParentGroupIndentLen() + } + + override fun setParentPropertyBlock(lastGroup: SqlBlock?) { + (lastGroup as? SqlUpdateSetGroupBlock)?.columnDefinitionGroupBlock = this + } + + override fun createBlockIndentLen(): Int { + parentBlock?.let { parent -> + if (parent is SqlUpdateSetGroupBlock) { + var parentLen = getKeywordNameLength(parent.childBlocks, 1) + return parent.indent.indentLen + .plus(parent.getNodeText().length) + .plus(1) + .plus(parentLen) + } + return offset + } ?: return offset + } + + private fun updateParentGroupIndentLen() { + parentBlock?.let { parent -> + if (parent is SqlUpdateSetGroupBlock) { + val parentLen = getKeywordNameLength(parent.childBlocks, 1) + parent.indent.groupIndentLen = + parent.indent.indentLen + .plus(parent.getNodeText().length) + .plus(parentLen) + } + } + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/update/SqlUpdateQueryGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/update/SqlUpdateQueryGroupBlock.kt new file mode 100644 index 00000000..e6456db7 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/update/SqlUpdateQueryGroupBlock.kt @@ -0,0 +1,68 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.keyword.update + +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.top.SqlTopQueryGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext +import org.domaframework.doma.intellij.formatter.util.SqlKeywordUtil + +class SqlUpdateQueryGroupBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlTopQueryGroupBlock( + node, + context, + ) { + var setQueryGroupBlock: SqlUpdateSetGroupBlock? = null + + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) + val preChildBlock = lastGroup?.childBlocks?.dropLast(1)?.lastOrNull() + indent.indentLevel = indentLevel + + val baseIndentLen = getBaseIndentLen(preChildBlock, lastGroup) + indent.groupIndentLen = baseIndentLen.plus(getNodeText().length) + indent.indentLen = baseIndentLen + createGroupIndentLen() + } + + override fun getBaseIndentLen( + preChildBlock: SqlBlock?, + block: SqlBlock?, + ): Int { + if (block == null) { + return createBlockIndentLen(preChildBlock) + } + if (preChildBlock == null) return createBlockIndentLen(preChildBlock) + + if (preChildBlock.indent.indentLevel == this.indent.indentLevel && + !SqlKeywordUtil.Companion.isSetLineKeyword(getNodeText(), preChildBlock.getNodeText()) + ) { + if (indent.indentLevel == IndentType.SECOND) { + val diffPreBlockTextLen = getNodeText().length.minus(preChildBlock.getNodeText().length) + return preChildBlock.indent.indentLen.minus(diffPreBlockTextLen) + } else { + val diffPretextLen = getNodeText().length.minus(preChildBlock.getNodeText().length) + return preChildBlock.indent.indentLen.minus(diffPretextLen) + } + } else { + return createBlockIndentLen(preChildBlock) + } + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/update/SqlUpdateSetGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/update/SqlUpdateSetGroupBlock.kt new file mode 100644 index 00000000..50bf59f0 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/update/SqlUpdateSetGroupBlock.kt @@ -0,0 +1,72 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.keyword.update + +import com.intellij.formatting.Indent +import com.intellij.lang.ASTNode +import com.intellij.psi.formatter.common.AbstractBlock +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateValueGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext + +open class SqlUpdateSetGroupBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlKeywordGroupBlock( + node, + IndentType.SECOND, + context, + ) { + val updateColumnRaws: MutableList = mutableListOf() + + // A block used for bulk updates. + // It contains a **column group**, an **equals sign (`=`)**, and a **value group block**. + var columnDefinitionGroupBlock: SqlUpdateColumnGroupBlock? = null + var assignmentSymbol: SqlUpdateColumnAssignmentSymbolBlock? = null + var valueGroupBlock: SqlUpdateValueGroupBlock? = null + + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) + indent.indentLevel = IndentType.SECOND + indent.indentLen = createBlockIndentLen(null) + indent.groupIndentLen = indent.indentLen.plus(getNodeText().length) + } + + override fun setParentPropertyBlock(lastGroup: SqlBlock?) { + (lastGroup as? SqlUpdateQueryGroupBlock)?.setQueryGroupBlock = this + } + + override fun buildChildren(): MutableList = mutableListOf() + + override fun getIndent(): Indent? = Indent.getSpaceIndent(indent.indentLen) + + override fun createBlockIndentLen(preChildBlock: SqlBlock?): Int = + if (!isAdjustIndentOnEnter()) { + parentBlock?.let { parent -> + if (parent.indent.indentLevel == IndentType.SUB) { + parent.indent.groupIndentLen.plus(1) + } else { + val parentTextLen = parent.getNodeText().length + val diffTextLen = parentTextLen.minus(getNodeText().length) + parent.indent.indentLen.plus(diffTextLen) + } + } ?: 0 + } else { + 0 + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnDefinitionGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnDefinitionGroupBlock.kt deleted file mode 100644 index 30c8d780..00000000 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnDefinitionGroupBlock.kt +++ /dev/null @@ -1,58 +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.block.group.subgroup - -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap -import com.intellij.lang.ASTNode -import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.block.SqlBlock - -/** - * Column List Group Block attached to Create Table - */ -class SqlColumnDefinitionGroupBlock( - node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, -) : SqlSubGroupBlock( - node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, - ) { - var alignmentColumnName = "" - - // TODO:Customize indentation - val offset = 2 - - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) - indent.indentLen = createBlockIndentLen() - indent.groupIndentLen = indent.indentLen - } - - override fun buildChildren(): MutableList = mutableListOf() - - override fun createBlockIndentLen(): Int = offset -} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnGroupBlock.kt deleted file mode 100644 index 55de9b07..00000000 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnGroupBlock.kt +++ /dev/null @@ -1,79 +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.block.group.subgroup - -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap -import com.intellij.lang.ASTNode -import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType -import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock - -/** - * Group blocks when generating columns with subqueries - */ -class SqlColumnGroupBlock( - node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, -) : SqlSubGroupBlock( - node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, - ) { - var isFirstColumnGroup = getNodeText() != "," - - override val indent = - ElementIndent( - IndentType.COLUMN, - 0, - 0, - ) - - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) - indent.indentLevel = IndentType.COLUMN - indent.indentLen = createBlockIndentLen() - indent.groupIndentLen = - if (isFirstColumnGroup) indent.indentLen else indent.indentLen.plus(1) - } - - override fun buildChildren(): MutableList = mutableListOf() - - override fun createBlockIndentLen(): Int = - parentBlock?.let { - if (it is SqlKeywordGroupBlock) { - val parentIndentLen = it.indent.indentLen.plus(it.getNodeText().length) - val subGroup = it.parentBlock as? SqlSubGroupBlock - if (subGroup is SqlSubGroupBlock && !subGroup.isFirstLineComment) { - parentIndentLen.plus(3) - } else { - parentIndentLen.plus(1) - } - } else { - it.indent.groupIndentLen.plus(1) - } - } ?: 1 -} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnRawGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnRawGroupBlock.kt new file mode 100644 index 00000000..304c69f4 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnRawGroupBlock.kt @@ -0,0 +1,74 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.subgroup + +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.group.column.SqlRawGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlSelectKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateColumnGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext + +/** + * Group blocks when generating columns with subqueries. + * Represents a group consisting of a single column row. + * For Example: + * SELECT id -- "id" is [SqlColumnRawGroupBlock](isFirstColumnGroup = true) + * , name -- "," is [SqlColumnRawGroupBlock] + */ +class SqlColumnRawGroupBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlRawGroupBlock( + node, + context, + ) { + var isFirstColumnGroup = getNodeText() != "," + + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) + indent.indentLevel = IndentType.COLUMN + indent.indentLen = createBlockIndentLen() + indent.groupIndentLen = + if (isFirstColumnGroup) indent.indentLen else indent.indentLen.plus(1) + } + + override fun setParentPropertyBlock(lastGroup: SqlBlock?) { + when (lastGroup) { + is SqlSelectKeywordGroupBlock -> lastGroup.selectionColumns.add(this) + is SqlUpdateColumnGroupBlock -> lastGroup.columnRawGroupBlocks.add(this) + } + (lastGroup as? SqlSelectKeywordGroupBlock)?.selectionColumns?.add(this) + } + + override fun createBlockIndentLen(): Int = + parentBlock?.let { parent -> + if (parent is SqlKeywordGroupBlock) { + val parentIndentLen = parent.indent.indentLen.plus(parent.getNodeText().length) + + val subGroup = parent.parentBlock as? SqlSubGroupBlock + if (subGroup is SqlSubGroupBlock && !subGroup.isFirstLineComment) { + parentIndentLen.plus(3) + } else { + parentIndentLen.plus(1) + } + } else { + parent.indent.groupIndentLen.plus(1) + } + } ?: 1 +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnSelectionGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnSelectionGroupBlock.kt new file mode 100644 index 00000000..47fff8ec --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlColumnSelectionGroupBlock.kt @@ -0,0 +1,30 @@ +/* + * Copyright Doma Tools Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.domaframework.doma.intellij.formatter.block.group.subgroup + +import com.intellij.lang.ASTNode +import com.intellij.psi.formatter.common.AbstractBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext + +abstract class SqlColumnSelectionGroupBlock( + node: ASTNode, + context: SqlBlockFormattingContext, +) : SqlSubGroupBlock( + node, + context, + ) { + override fun buildChildren(): MutableList = mutableListOf() +} 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 2754622c..9f512389 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 @@ -15,31 +15,20 @@ */ package org.domaframework.doma.intellij.formatter.block.group.subgroup -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode -import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext /** - * The parent must be [org.domaframework.doma.intellij.formatter.block.group.SqlColumnDefinitionRawGroupBlock] + * The parent must be [org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnDefinitionRawGroupBlock] */ class SqlDataTypeParamBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlSubGroupBlock( node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override val indent = ElementIndent( @@ -48,8 +37,8 @@ class SqlDataTypeParamBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.PARAM indent.indentLen = 0 indent.groupIndentLen = 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 bc3e83df..265f5ff8 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 @@ -15,28 +15,17 @@ */ package org.domaframework.doma.intellij.formatter.block.group.subgroup -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode -import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext class SqlFunctionParamBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlSubGroupBlock( node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override val indent = ElementIndent( @@ -45,8 +34,8 @@ class SqlFunctionParamBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLevel = IndentType.PARAM indent.indentLen = 0 indent.groupIndentLen = 0 diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlInsertColumnGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlInsertColumnGroupBlock.kt deleted file mode 100644 index 48e8bb1b..00000000 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlInsertColumnGroupBlock.kt +++ /dev/null @@ -1,90 +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.block.group.subgroup - -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap -import com.intellij.lang.ASTNode -import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInsertKeywordGroupBlock -import org.domaframework.doma.intellij.psi.SqlTypes - -/** - * Block of columns to insert - */ -class SqlInsertColumnGroupBlock( - node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, -) : SqlSubGroupBlock( - node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, - ) { - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) - indent.indentLen = createBlockIndentLen() - indent.groupIndentLen = indent.indentLen.plus(1) - updateParentGroupIndentLen() - } - - override fun buildChildren(): MutableList = mutableListOf() - - override fun createBlockIndentLen(): Int { - parentBlock?.let { - if (it is SqlInsertKeywordGroupBlock) { - var parentLen = 0 - val keywords = - it.childBlocks.dropLast(1).takeWhile { it.node.elementType == SqlTypes.KEYWORD } - keywords.forEach { keyword -> - parentLen = parentLen.plus(keyword.getNodeText().length).plus(1) - } - return it.indent.indentLen - .plus(it.getNodeText().length) - .plus(1) - .plus(parentLen) - } - // TODO:Customize indentation - return 2 - } ?: return 2 - } - - private fun updateParentGroupIndentLen() { - parentBlock?.let { - if (it is SqlInsertKeywordGroupBlock) { - var parentLen = 0 - val keywords = - it.childBlocks.dropLast(1).takeWhile { it.node.elementType == SqlTypes.KEYWORD } - keywords.forEach { keyword -> - parentLen = parentLen.plus(keyword.getNodeText().length).plus(1) - } - it.indent.groupIndentLen = - it.indent.indentLen - .plus(it.getNodeText().length) - .plus(parentLen) - } - } - } -} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlParallelListBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlParallelListBlock.kt index 8be12c37..0eaed59d 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlParallelListBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlParallelListBlock.kt @@ -15,13 +15,10 @@ */ package org.domaframework.doma.intellij.formatter.block.group.subgroup -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode -import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext /** * A class that represents the List type test data after the IN clause. @@ -31,18 +28,10 @@ import org.domaframework.doma.intellij.formatter.block.SqlBlock */ class SqlParallelListBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlSubQueryGroupBlock( node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override val indent = ElementIndent( @@ -51,7 +40,7 @@ class SqlParallelListBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) } } 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 c6f8477f..9e6ed5f7 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 @@ -15,34 +15,26 @@ */ package org.domaframework.doma.intellij.formatter.block.group.subgroup -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap +import com.intellij.formatting.Block +import com.intellij.formatting.Spacing import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock -import org.domaframework.doma.intellij.formatter.IndentType import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.SqlCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock 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 abstract class SqlSubGroupBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlNewGroupBlock( node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { var isFirstLineComment = false var prevChildren: List? = emptyList() + var endPatternBlock: SqlRightPatternBlock? = null override val indent = ElementIndent( @@ -51,12 +43,14 @@ abstract class SqlSubGroupBlock( 0, ) - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) prevChildren = parentBlock?.childBlocks?.toList() indent.indentLevel = indent.indentLevel indent.indentLen = createBlockIndentLen() - indent.groupIndentLen = indent.indentLen.plus(getNodeText().length) + indent.groupIndentLen = parentBlock?.let { parent -> + parent.indent.indentLen.plus(parent.getNodeText().length.plus(1)) + } ?: indent.indentLen.plus(getNodeText().length) } override fun addChildBlock(childBlock: SqlBlock) { @@ -67,4 +61,13 @@ abstract class SqlSubGroupBlock( } override fun buildChildren(): MutableList = mutableListOf() + + override fun getSpacing( + p0: Block?, + p1: Block, + ): Spacing? = null + + override fun isLeaf(): Boolean = true + + open fun endGroup() {} } 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 e549bf95..ab10fe45 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 @@ -15,33 +15,21 @@ */ package org.domaframework.doma.intellij.formatter.block.group.subgroup -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlJoinGroupBlock -import org.domaframework.doma.intellij.psi.SqlTypes +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext open class SqlSubQueryGroupBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlSubGroupBlock( node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLen = createBlockIndentLen() indent.groupIndentLen = createGroupIndentLen() } @@ -53,31 +41,24 @@ open class SqlSubQueryGroupBlock( private fun createGroupIndentLen(): Int { parentBlock?.let { parent -> if (parent is SqlJoinGroupBlock) { - var parentLen = 0 - val keywords = - parent.childBlocks.dropLast(1).takeWhile { parent.node.elementType == SqlTypes.KEYWORD } - keywords.forEach { keyword -> - parentLen = parentLen.plus(keyword.getNodeText().length).plus(1) - } + var parentLen = getKeywordNameLength(parent.childBlocks, 1) return parent.indent.indentLen .plus(parent.getNodeText().length) .plus(2) .plus(parentLen) - } else { - var parentLen = 0 - val prevBlocks = - prevChildren - ?.dropLast(1) - ?.filter { it.node.startOffset > parent.node.startOffset } - prevBlocks - ?.forEach { prev -> - parentLen = parentLen.plus(prev.getNodeText().length).plus(1) - } - return parent.indent.groupIndentLen - .plus(parentLen) - .plus(2) } + + var parentLen = 0 + val prevBlocks = + prevChildren + ?.dropLast(1) + ?.filter { it.node.startOffset > parent.node.startOffset } + prevBlocks + ?.forEach { prev -> + parentLen = parentLen.plus(prev.getNodeText().length).plus(1) + } return parent.indent.groupIndentLen + .plus(parentLen) .plus(2) } ?: return 1 } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlUpdateColumnGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlUpdateColumnGroupBlock.kt index ed493a2c..873d6504 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlUpdateColumnGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlUpdateColumnGroupBlock.kt @@ -15,14 +15,11 @@ */ package org.domaframework.doma.intellij.formatter.block.group.subgroup -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.block.SqlBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlUpdateKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext import org.domaframework.doma.intellij.psi.SqlTypes /** @@ -31,18 +28,10 @@ import org.domaframework.doma.intellij.psi.SqlTypes */ class SqlUpdateColumnGroupBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlSubGroupBlock( node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { override fun setParentGroupBlock(block: SqlBlock?) { super.setParentGroupBlock(block) diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlUpdateValueGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlUpdateValueGroupBlock.kt index 628e6345..26416931 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlUpdateValueGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlUpdateValueGroupBlock.kt @@ -15,14 +15,11 @@ */ package org.domaframework.doma.intellij.formatter.block.group.subgroup -import com.intellij.formatting.Alignment -import com.intellij.formatting.FormattingMode -import com.intellij.formatting.SpacingBuilder -import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode import com.intellij.psi.formatter.common.AbstractBlock import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlUpdateKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateSetGroupBlock +import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext /** * In an UPDATE statement using the row value constructor, @@ -30,46 +27,44 @@ import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlUpdateKe */ class SqlUpdateValueGroupBlock( node: ASTNode, - wrap: Wrap?, - alignment: Alignment?, - spacingBuilder: SpacingBuilder, - enableFormat: Boolean, - formatMode: FormattingMode, + context: SqlBlockFormattingContext, ) : SqlSubGroupBlock( node, - wrap, - alignment, - spacingBuilder, - enableFormat, - formatMode, + context, ) { - override fun setParentGroupBlock(block: SqlBlock?) { - super.setParentGroupBlock(block) + // TODO:Customize indentation + private val offset = 2 + + override fun setParentGroupBlock(lastGroup: SqlBlock?) { + super.setParentGroupBlock(lastGroup) indent.indentLen = createBlockIndentLen() indent.groupIndentLen = createGroupIndentLen() } + override fun setParentPropertyBlock(lastGroup: SqlBlock?) { + (lastGroup as? SqlUpdateSetGroupBlock)?.valueGroupBlock = this + } + override fun buildChildren(): MutableList = mutableListOf() override fun createBlockIndentLen(): Int { parentBlock?.let { parent -> - if (parent is SqlUpdateKeywordGroupBlock) { + if (parent is SqlUpdateSetGroupBlock) { return parent.indent.indentLen .plus(parent.getNodeText().length) .plus(3) } - // TODO:Customize indentation - return 2 - } ?: return 2 + return offset + } ?: return offset } private fun createGroupIndentLen(): Int { parentBlock?.let { parent -> - if (parent is SqlUpdateKeywordGroupBlock) { + if (parent is SqlUpdateSetGroupBlock) { val parentGroupIndent = parent.indent.groupIndentLen return parentGroupIndent.plus(4) } - } ?: return 2 - return 2 + } ?: return offset + return offset } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlBlockBuilder.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt similarity index 85% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlBlockBuilder.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt index 8fd90e3a..10379e23 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlBlockBuilder.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockBuilder.kt @@ -13,26 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter +package org.domaframework.doma.intellij.formatter.builder import org.domaframework.doma.intellij.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.SqlCommentBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock 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.subgroup.SqlSubGroupBlock +import org.domaframework.doma.intellij.formatter.util.IndentType open class SqlBlockBuilder { - private val groupTopNodeIndexHistory = mutableListOf>() + private val groupTopNodeIndexHistory = mutableListOf() private val commentBlocks = mutableListOf() private val conditionOrLoopBlocks = mutableListOf() - fun getGroupTopNodeIndexHistory(): List> = groupTopNodeIndexHistory + fun getGroupTopNodeIndexHistory(): List = groupTopNodeIndexHistory - fun getLastGroup(): SqlBlock? = groupTopNodeIndexHistory.lastOrNull()?.second - - fun addGroupTopNodeIndexHistory(block: Pair) { + fun addGroupTopNodeIndexHistory(block: SqlBlock) { groupTopNodeIndexHistory.add(block) } @@ -69,7 +68,7 @@ open class SqlBlockBuilder { } } - fun getLastGroupTopNodeIndexHistory(): Pair? = groupTopNodeIndexHistory.lastOrNull() + fun getLastGroupTopNodeIndexHistory(): SqlBlock? = groupTopNodeIndexHistory.lastOrNull() fun removeLastGroupTopNodeIndexHistory() { if (groupTopNodeIndexHistory.isNotEmpty()) { @@ -87,7 +86,7 @@ open class SqlBlockBuilder { fun getGroupTopNodeIndex(condition: (SqlBlock) -> Boolean): Int = groupTopNodeIndexHistory.indexOfLast { - condition(it.second) + condition(it) } fun getConditionOrLoopBlocksLast(): SqlElConditionLoopCommentBlock? = conditionOrLoopBlocks.lastOrNull() diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlCustomSpacingBuilder.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlCustomSpacingBuilder.kt similarity index 90% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlCustomSpacingBuilder.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlCustomSpacingBuilder.kt index 825c4b51..695d28b2 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlCustomSpacingBuilder.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlCustomSpacingBuilder.kt @@ -13,22 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.domaframework.doma.intellij.formatter +package org.domaframework.doma.intellij.formatter.builder 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.formatter.block.SqlBlock -import org.domaframework.doma.intellij.formatter.block.SqlColumnBlock -import org.domaframework.doma.intellij.formatter.block.SqlRightPatternBlock import org.domaframework.doma.intellij.formatter.block.SqlWhitespaceBlock -import org.domaframework.doma.intellij.formatter.block.group.SqlColumnDefinitionRawGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.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.SqlColumnDefinitionGroupBlock +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.subgroup.SqlDataTypeParamBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlParallelListBlock -import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlRightPatternBlock import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateValueGroupBlock class SqlCustomSpacingBuilder { @@ -124,7 +124,7 @@ class SqlCustomSpacingBuilder { fun getSpacingRightPattern(block: SqlRightPatternBlock): Spacing? { return when { - block.parentBlock is SqlColumnDefinitionGroupBlock || + block.parentBlock is SqlCreateTableColumnDefinitionGroupBlock || block.parentBlock is SqlUpdateColumnGroupBlock || block.parentBlock is SqlUpdateValueGroupBlock -> { return getSpacing(block) diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlFormattingModelBuilder.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlFormattingModelBuilder.kt similarity index 98% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlFormattingModelBuilder.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlFormattingModelBuilder.kt index 050d631c..0155c0db 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlFormattingModelBuilder.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlFormattingModelBuilder.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 +package org.domaframework.doma.intellij.formatter.builder import com.intellij.formatting.Alignment import com.intellij.formatting.FormattingContext diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatPreProcessor.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlFormatPreProcessor.kt similarity index 82% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatPreProcessor.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlFormatPreProcessor.kt index 1a72a49a..79818db5 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatPreProcessor.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlFormatPreProcessor.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 +package org.domaframework.doma.intellij.formatter.processor import com.intellij.lang.ASTNode import com.intellij.openapi.editor.Document @@ -21,17 +21,15 @@ import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile -import com.intellij.psi.PsiRecursiveElementVisitor import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.TokenType import com.intellij.psi.impl.source.codeStyle.PreFormatProcessor -import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.elementType import com.intellij.psi.util.prevLeafs import org.domaframework.doma.intellij.common.util.PluginLoggerUtil -import org.domaframework.doma.intellij.extension.expr.isConditionOrLoopDirective -import org.domaframework.doma.intellij.psi.SqlBlockComment -import org.domaframework.doma.intellij.psi.SqlCustomElCommentExpr +import org.domaframework.doma.intellij.formatter.util.CreateQueryType +import org.domaframework.doma.intellij.formatter.util.SqlKeywordUtil +import org.domaframework.doma.intellij.formatter.visitor.SqlFormatVisitor import org.domaframework.doma.intellij.psi.SqlTypes import org.domaframework.doma.intellij.setting.SqlLanguage import org.jetbrains.kotlin.psi.psiUtil.startOffset @@ -128,10 +126,10 @@ class SqlFormatPreProcessor : PreFormatProcessor { removeSpacesAroundNewline(document, it.textRange) } else { val isNewLineGroup = - SqlKeywordUtil.getIndentType(nextElement.text ?: "").isNewLineGroup() + SqlKeywordUtil.Companion.getIndentType(nextElement.text ?: "").isNewLineGroup() val isSetLineKeyword = if (keywordIndex > 0) { - SqlKeywordUtil.isSetLineKeyword( + SqlKeywordUtil.Companion.isSetLineKeyword( nextElement.text, replaceKeywordList[keywordIndex - 1].text, ) @@ -180,9 +178,9 @@ class SqlFormatPreProcessor : PreFormatProcessor { getNewLineString(element.prevSibling, getUpperText(element)) } else if (isSubGroupFirstElement(element)) { getUpperText(element) - } else if (SqlKeywordUtil.getIndentType(element.text).isNewLineGroup()) { + } else if (SqlKeywordUtil.Companion.getIndentType(element.text).isNewLineGroup()) { if (index > 0 && - SqlKeywordUtil.isSetLineKeyword( + SqlKeywordUtil.Companion.isSetLineKeyword( element.text, keywordList[index - 1].text, ) @@ -274,12 +272,12 @@ class SqlFormatPreProcessor : PreFormatProcessor { it.elementType == SqlTypes.KEYWORD }.asReversed() .forEach { key -> - if (SqlKeywordUtil.isTopKeyword(key.text)) { + if (SqlKeywordUtil.Companion.isTopKeyword(key.text)) { topLastKeyWord = key return@forEach } - if (SqlKeywordUtil.isAttachedKeyword(key.text)) { - attachmentKeywordType = CreateQueryType.getCreateTableType(key.text) + if (SqlKeywordUtil.Companion.isAttachedKeyword(key.text)) { + attachmentKeywordType = CreateQueryType.Companion.getCreateTableType(key.text) } } val prevKeywordText = topLastKeyWord?.text?.lowercase() @@ -323,7 +321,7 @@ class SqlFormatPreProcessor : PreFormatProcessor { .findLast { it !is PsiWhiteSpace } == null private fun logging() { - PluginLoggerUtil.countLogging( + PluginLoggerUtil.Companion.countLogging( this::class.java.simpleName, "SqlFormat", "Format", @@ -331,56 +329,3 @@ class SqlFormatPreProcessor : PreFormatProcessor { ) } } - -private class SqlFormatVisitor : PsiRecursiveElementVisitor() { - val replaces = mutableListOf() - var lastElement: PsiElement? = null - - override fun visitElement(element: PsiElement) { - super.visitElement(element) - if (element !is PsiFile && element.nextSibling == null) { - lastElement = element - } - - if (PsiTreeUtil.getParentOfType(element, SqlBlockComment::class.java) == null) { - when (element.elementType) { - SqlTypes.KEYWORD, SqlTypes.COMMA, SqlTypes.LEFT_PAREN, SqlTypes.RIGHT_PAREN, SqlTypes.WORD -> { - replaces.add(element) - } - - SqlTypes.OTHER -> { - if (element.text == "=") { - val updateSetKeyword = - replaces - .lastOrNull { it.elementType == SqlTypes.KEYWORD } - if (updateSetKeyword?.text?.lowercase() == "set") { - replaces.add(element) - } - } - } - - SqlTypes.BLOCK_COMMENT -> - if ( - element is SqlCustomElCommentExpr && - element.isConditionOrLoopDirective() - ) { - replaces.add(element) - } - } - } - } - - override fun visitWhiteSpace(space: PsiWhiteSpace) { - super.visitWhiteSpace(space) - val nextElement = space.nextSibling - if (nextElement != null && - ( - space.text.contains("\n") || - nextElement.elementType == SqlTypes.LINE_COMMENT || - nextElement.elementType == SqlTypes.BLOCK_COMMENT - ) - ) { - replaces.add(space) - } - } -} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlPostProcessor.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlPostProcessor.kt similarity index 97% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlPostProcessor.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlPostProcessor.kt index 2b4b5e27..69eef4c7 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlPostProcessor.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlPostProcessor.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 +package org.domaframework.doma.intellij.formatter.processor import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.command.WriteCommandAction 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 new file mode 100644 index 00000000..8fe0d6d1 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt @@ -0,0 +1,316 @@ +/* + * 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.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.expr.SqlElConditionLoopCommentBlock +import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnDefinitionRawGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInlineGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInlineSecondGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateViewGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnRawGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlRightPatternBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock +import org.domaframework.doma.intellij.formatter.builder.SqlBlockBuilder +import org.domaframework.doma.intellij.formatter.util.IndentType +import org.domaframework.doma.intellij.formatter.util.SqlKeywordUtil +import org.domaframework.doma.intellij.psi.SqlTypes + +class SqlSetParentGroupProcessor( + private val blockBuilder: SqlBlockBuilder, +) { + data class SetParentContext( + val childBlock: SqlBlock, + val blockBuilder: SqlBlockBuilder, + ) + + /** + * Sets the parent of the latest group block and registers itself as a child element. + */ + fun updateGroupBlockParentAndAddGroup(childBlock: SqlBlock) { + val context = + SetParentContext( + childBlock, + blockBuilder, + ) + setParentGroups(context) { history -> + return@setParentGroups history.last() + } + } + + /** + * Does not set a parent. + */ + fun updateGroupBlockAddGroup(childBlock: SqlBlock) { + setParentGroups( + SetParentContext( + childBlock, + blockBuilder, + ), + ) { history -> + return@setParentGroups null + } + } + + /** + * Registers itself as a child element in the same block as the parent of the last group at the time of processing. + */ + fun updateGroupBlockLastGroupParentAddGroup( + lastGroupBlock: SqlBlock, + childBlock: SqlBlock, + ) { + setParentGroups( + SetParentContext( + childBlock, + blockBuilder, + ), + ) { history -> + return@setParentGroups lastGroupBlock.parentBlock + } + } + + fun updateKeywordGroupBlockParentAndAddGroup( + lastGroupBlock: SqlBlock, + lastIndentLevel: IndentType, + childBlock: SqlKeywordGroupBlock, + ) { + val context = + SetParentContext( + childBlock, + blockBuilder, + ) + + if (lastGroupBlock.indent.indentLevel == IndentType.SUB) { + setParentGroups(context) { history -> + return@setParentGroups lastGroupBlock + } + } else if (lastIndentLevel == childBlock.indent.indentLevel) { + blockBuilder.removeLastGroupTopNodeIndexHistory() + updateGroupBlockLastGroupParentAddGroup( + lastGroupBlock, + childBlock, + ) + } else if (lastIndentLevel < childBlock.indent.indentLevel) { + updateGroupBlockParentAndAddGroup( + childBlock, + ) + } else { + if (lastIndentLevel == IndentType.JOIN && + SqlKeywordUtil.Companion.isSecondOptionKeyword(childBlock.getNodeText()) + ) { + // left,right < inner,outer < join + updateGroupBlockParentAndAddGroup( + childBlock, + ) + return + } + + setParentGroups(context) { history -> + return@setParentGroups history + .lastOrNull { it.indent.indentLevel < childBlock.indent.indentLevel } + } + } + } + + fun updateColumnDefinitionRawGroupBlockParentAndAddGroup( + lastGroupBlock: SqlBlock, + lastIndentLevel: IndentType, + childBlock: SqlColumnDefinitionRawGroupBlock, + ) { + when (lastIndentLevel) { + childBlock.indent.indentLevel -> { + blockBuilder.removeLastGroupTopNodeIndexHistory() + updateGroupBlockLastGroupParentAddGroup( + lastGroupBlock, + childBlock, + ) + } + + else -> { + updateGroupBlockParentAndAddGroup(childBlock) + } + } + } + + fun updateColumnRawGroupBlockParentAndAddGroup( + lastGroupBlock: SqlBlock, + childBlock: SqlColumnRawGroupBlock, + ) { + if (lastGroupBlock is SqlColumnRawGroupBlock) { + blockBuilder.removeLastGroupTopNodeIndexHistory() + } + updateGroupBlockParentAndAddGroup(childBlock) + } + + fun updateInlineSecondGroupBlockParentAndAddGroup( + lastGroupBlock: SqlBlock, + lastIndentLevel: IndentType, + childBlock: SqlInlineSecondGroupBlock, + ) { + val context = + SetParentContext( + childBlock, + blockBuilder, + ) + if (childBlock.isEndCase) { + val inlineIndex = + blockBuilder.getGroupTopNodeIndex { block -> + block.indent.indentLevel == IndentType.INLINE + } + if (inlineIndex >= 0) { + setParentGroups( + context, + ) { history -> + return@setParentGroups history[inlineIndex] + } + blockBuilder.clearSubListGroupTopNodeIndexHistory(inlineIndex) + } + return + } + if (lastIndentLevel == IndentType.INLINE_SECOND) { + blockBuilder.removeLastGroupTopNodeIndexHistory() + updateGroupBlockLastGroupParentAddGroup( + lastGroupBlock, + childBlock, + ) + return + } + updateGroupBlockParentAndAddGroup( + childBlock, + ) + } + + fun updateConditionLoopCommentBlockParent( + lastGroupBlock: SqlBlock, + childBlock: SqlElConditionLoopCommentBlock, + ) { + if (lastGroupBlock is SqlCommaBlock || lastGroupBlock is SqlElConditionLoopCommentBlock) { + blockBuilder.removeLastGroupTopNodeIndexHistory() + } + setParentGroups( + SetParentContext( + childBlock, + blockBuilder, + ), + ) { history -> + if (childBlock.conditionType.isEnd()) { + val lastConditionLoopCommentBlock = + blockBuilder.getConditionOrLoopBlocksLast() + blockBuilder.removeConditionOrLoopBlockLast() + return@setParentGroups lastConditionLoopCommentBlock + } + return@setParentGroups null + } + } + + fun updateSqlRightPatternBlockParent(childBlock: SqlRightPatternBlock) { + val paramIndex = + blockBuilder.getGroupTopNodeIndex { block -> + block is SqlSubGroupBlock + } + if (paramIndex >= 0) { + val context = + SetParentContext( + childBlock, + blockBuilder, + ) + setParentGroups(context) { history -> + return@setParentGroups history[paramIndex] + } + + if (childBlock.parentBlock is SqlSubGroupBlock) { + (childBlock.parentBlock as SqlSubGroupBlock).endGroup() + } + blockBuilder.clearSubListGroupTopNodeIndexHistory(paramIndex) + } + } + + /** + * Determines its parent group and, if conditions are met, registers itself as a new group block in the list. + */ + private fun setParentGroups( + context: SetParentContext, + getParentGroup: (MutableList) -> SqlBlock?, + ) { + val parentGroup = + getParentGroup(context.blockBuilder.getGroupTopNodeIndexHistory() as MutableList) + + // // The parent block for SqlElConditionLoopCommentBlock will be set later + if (context.childBlock !is SqlElConditionLoopCommentBlock || + context.childBlock.conditionType.isEnd() + ) { + context.childBlock.setParentGroupBlock(parentGroup) + } + + val expectedClassTypes = + listOf( + SqlSubGroupBlock::class, + SqlCreateViewGroupBlock::class, + SqlInlineGroupBlock::class, + SqlInlineSecondGroupBlock::class, + SqlColumnDefinitionRawGroupBlock::class, + ) + if (isNewGroup(context.childBlock, context.blockBuilder) || isExpectedClassType(expectedClassTypes, 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) + } + } + + /** + * Determines whether it is a group that requires a line break or a specific combination of keywords that does not require a line break. + */ + private fun isNewGroup( + childBlock: SqlBlock, + blockBuilder: SqlBlockBuilder, + ): Boolean { + val lastGroup = blockBuilder.getLastGroupTopNodeIndexHistory() + return isNewGroupAndNotSetLineKeywords(childBlock, lastGroup) + } + + fun isNewGroupAndNotSetLineKeywords( + childBlock: SqlBlock, + lastGroup: SqlBlock?, + ): Boolean { + val isNewGroupType = childBlock.indent.indentLevel.isNewLineGroup() + val lastKeywordText = + if (lastGroup?.indent?.indentLevel == IndentType.JOIN) { + lastGroup.getNodeText() + } else { + getLastGroupKeywordText(lastGroup) + } + + val isSetLineGroup = + SqlKeywordUtil.Companion.isSetLineKeyword( + childBlock.getNodeText(), + lastKeywordText, + ) + return isNewGroupType && !isSetLineGroup + } + + /** + * 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() ?: "" +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CreateTableUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CreateTableUtil.kt new file mode 100644 index 00000000..22e2fbac --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/CreateTableUtil.kt @@ -0,0 +1,103 @@ +/* + * 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.formatting.Block +import com.intellij.formatting.Spacing +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.SqlWhitespaceBlock +import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnBlock +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.psi.SqlTypes + +object CreateTableUtil { + fun getCreateTableClauseSubGroup( + lastGroup: SqlBlock, + child: ASTNode, + sqlBlockFormattingCtx: SqlBlockFormattingContext, + ): SqlCreateTableColumnDefinitionGroupBlock? { + if (lastGroup is SqlCreateKeywordGroupBlock) { + return SqlCreateTableColumnDefinitionGroupBlock(child, sqlBlockFormattingCtx) + } + return null + } + + fun getColumnRawGroup( + lastGroup: SqlBlock?, + child: ASTNode, + sqlBlockFormattingCtx: SqlBlockFormattingContext, + ): SqlCreateTableColumnDefinitionRawGroupBlock? = + if (lastGroup is SqlCreateTableColumnDefinitionGroupBlock || + lastGroup is SqlCreateTableColumnDefinitionRawGroupBlock + ) { + SqlCreateTableColumnDefinitionRawGroupBlock( + child, + sqlBlockFormattingCtx, + ) + } else { + null + } + + /** + * Right-justify based on the longest column name in the column definition line + */ + fun getColumnDefinitionRawGroupSpacing( + child1: Block?, + child2: Block, + ): Spacing? { + // TODO Customize indentation + val offset = 5 + + // Top Column Definition Group Block + if (child1 is SqlWhitespaceBlock && child2 is SqlCreateTableColumnDefinitionRawGroupBlock) { + val columnDefinitionGroupBlock = + child2.parentBlock as? SqlCreateTableColumnDefinitionGroupBlock ?: return null + + if (child2.node.elementType == SqlTypes.COMMA) { + // If the child2 is a comma, it is not a column definition raw group block. + return Spacing.createSpacing(offset, offset, 0, false, 0, 0) + } + + val maxColumnName = columnDefinitionGroupBlock.getMaxColumnNameLength() + val diffColumnNameLen = + maxColumnName.minus(child2.columnBlock?.getNodeText()?.length ?: 0) + // If the longest column name is not in the top row, add two spaces for the "," to match the row with a comma. + var indentLen = offset.plus(diffColumnNameLen) + val maxColumnNameRaw = + columnDefinitionGroupBlock.columnRawGroupBlocks + .findLast { raw -> raw.columnBlock?.getNodeText()?.length == maxColumnName } + if (maxColumnNameRaw?.isFirstColumnRaw != true) { + indentLen = indentLen.plus(2) + } + + return Spacing.createSpacing(indentLen, indentLen, 0, false, 0, 0) + } + + if (child1 is SqlCreateTableColumnDefinitionRawGroupBlock && child2 is SqlColumnBlock) { + val columnDefinitionGroupBlock = + child1.parentBlock as? SqlCreateTableColumnDefinitionGroupBlock ?: return null + + val maxColumnName = columnDefinitionGroupBlock.getMaxColumnNameLength() + val diffColumnNameLen = maxColumnName.minus(child2.getNodeText().length) + var indentLen = diffColumnNameLen.plus(1) + return Spacing.createSpacing(indentLen, indentLen, 0, false, 0, 0) + } + return null + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/InsertClauseUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/InsertClauseUtil.kt new file mode 100644 index 00000000..dd5e43dd --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/InsertClauseUtil.kt @@ -0,0 +1,34 @@ +/* + * 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.group.keyword.insert.SqlInsertColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertQueryGroupBlock + +object InsertClauseUtil { + fun getInsertClauseSubGroup( + lastGroup: SqlBlock, + child: ASTNode, + sqlBlockFormattingCtx: SqlBlockFormattingContext, + ): SqlInsertColumnGroupBlock? { + if (lastGroup is SqlInsertQueryGroupBlock) { + return SqlInsertColumnGroupBlock(child, sqlBlockFormattingCtx) + } + return null + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/JoinGroupUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/JoinGroupUtil.kt new file mode 100644 index 00000000..f4ec5bb6 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/JoinGroupUtil.kt @@ -0,0 +1,49 @@ +/* + * 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.SqlKeywordBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlJoinGroupBlock + +object JoinGroupUtil { + fun getJoinKeywordGroupBlock( + lastGroupBlock: SqlBlock?, + keywordText: String, + child: ASTNode, + sqlBlockFormattingCtx: SqlBlockFormattingContext, + ): SqlBlock = + if (SqlKeywordUtil.isJoinKeyword(keywordText)) { + SqlJoinGroupBlock( + child, + sqlBlockFormattingCtx, + ) + } else if (lastGroupBlock is SqlJoinGroupBlock) { + // JOIN_ATTACHED_KEYWORD Keywords + SqlKeywordBlock( + child, + IndentType.ATTACHED, + sqlBlockFormattingCtx, + ) + } else { + // Catch any unregistered JOIN keywords here if they are not already listed in JOIN_KEYWORD. + SqlJoinGroupBlock( + child, + sqlBlockFormattingCtx, + ) + } +} 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 new file mode 100644 index 00000000..cddbe071 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/NotQueryGroupUtil.kt @@ -0,0 +1,36 @@ +/* + * 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.group.subgroup.SqlParallelListBlock + +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) + } + 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/SqlBlockUtil.kt new file mode 100644 index 00000000..75532159 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockUtil.kt @@ -0,0 +1,356 @@ +/* + * 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.formatting.Alignment +import com.intellij.formatting.FormattingMode +import com.intellij.formatting.SpacingBuilder +import com.intellij.formatting.Wrap +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiComment +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.psi.util.elementType +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.SqlTableBlock +import org.domaframework.doma.intellij.formatter.block.SqlWordBlock +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.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.keyword.SqlInlineGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInlineSecondGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.condition.SqlConditionKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.condition.SqlConditionalExpressionGroupBlock +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.block.group.keyword.create.SqlCreateViewGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertQueryGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.top.SqlSelectQueryGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateQueryGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateSetGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlColumnRawGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlDataTypeParamBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlFunctionParamBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock +import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder +import org.domaframework.doma.intellij.psi.SqlCustomElCommentExpr +import org.domaframework.doma.intellij.psi.SqlTypes + +data class SqlBlockFormattingContext( + val wrap: Wrap?, + val alignment: Alignment?, + val spacingBuilder: SpacingBuilder, + val enableFormat: Boolean, + val formatMode: FormattingMode, +) + +class SqlBlockUtil( + sqlBlock: SqlBlock, + enableFormat: Boolean, + formatMode: FormattingMode, +) { + val sqlBlockFormattingCtx = + SqlBlockFormattingContext( + sqlBlock.wrap, + sqlBlock.alignment, + sqlBlock.spacingBuilder, + enableFormat, + formatMode, + ) + + fun getKeywordBlock( + child: ASTNode, + lastGroupBlock: SqlBlock?, + ): SqlBlock { + // Because we haven't yet set the parent-child relationship of the block, + // the parent group references groupTopNodeIndexHistory. + val keywordText = child.text.lowercase() + val indentLevel = SqlKeywordUtil.getIndentType(keywordText) + + if (indentLevel.isNewLineGroup()) { + return getKeywordGroupBlock(indentLevel, keywordText, child, lastGroupBlock) + } + + when (indentLevel) { + IndentType.INLINE -> { + if (!SqlKeywordUtil.isSetLineKeyword( + child.text, + lastGroupBlock?.getNodeText() ?: "", + ) + ) { + return SqlInlineGroupBlock(child, sqlBlockFormattingCtx) + } + } + + IndentType.ATTACHED -> { + if (lastGroupBlock is SqlCreateKeywordGroupBlock) { + lastGroupBlock.setCreateQueryType(child.text) + return SqlKeywordBlock(child, indentLevel, sqlBlockFormattingCtx) + } + } + + IndentType.OPTIONS -> { + if (child.text.lowercase() == "as") { + val parentCreateBlock = + lastGroupBlock as? SqlCreateKeywordGroupBlock + ?: lastGroupBlock?.parentBlock as? SqlCreateKeywordGroupBlock + if (parentCreateBlock != null && parentCreateBlock.createType == CreateQueryType.VIEW) { + return SqlCreateViewGroupBlock(child, sqlBlockFormattingCtx) + } + } + } + + else -> return SqlKeywordBlock(child, indentLevel, sqlBlockFormattingCtx) + } + return SqlKeywordBlock(child, indentLevel, sqlBlockFormattingCtx) + } + + private fun getKeywordGroupBlock( + indentLevel: IndentType, + keywordText: String, + child: ASTNode, + lastGroupBlock: SqlBlock?, + ): SqlBlock = + when (indentLevel) { + IndentType.JOIN -> { + JoinGroupUtil.getJoinKeywordGroupBlock( + lastGroupBlock, + keywordText, + child, + sqlBlockFormattingCtx, + ) + } + + IndentType.INLINE_SECOND -> { + SqlInlineSecondGroupBlock( + child, + sqlBlockFormattingCtx, + ) + } + + IndentType.TOP -> { + when (keywordText) { + "select" -> + SqlSelectQueryGroupBlock( + child, + sqlBlockFormattingCtx, + ) + + "create" -> + SqlCreateKeywordGroupBlock( + child, + sqlBlockFormattingCtx, + ) + + "insert" -> + SqlInsertQueryGroupBlock( + child, + sqlBlockFormattingCtx, + ) + + "update" -> + SqlUpdateQueryGroupBlock( + child, + sqlBlockFormattingCtx, + ) + + else -> + SqlKeywordGroupBlock( + child, + indentLevel, + sqlBlockFormattingCtx, + ) + } + } + + IndentType.SECOND -> { + if (keywordText == "set") { + SqlUpdateSetGroupBlock( + child, + sqlBlockFormattingCtx, + ) + } else { + SqlKeywordGroupBlock( + child, + indentLevel, + sqlBlockFormattingCtx, + ) + } + } + + IndentType.SECOND_OPTION -> { + if (SqlKeywordUtil.isConditionKeyword(keywordText)) { + SqlConditionKeywordGroupBlock( + child, + sqlBlockFormattingCtx, + ) + } else { + SqlKeywordGroupBlock( + child, + indentLevel, + sqlBlockFormattingCtx, + ) + } + } + + else -> { + SqlKeywordGroupBlock( + child, + indentLevel, + sqlBlockFormattingCtx, + ) + } + } + + fun getSubGroupBlock( + lastGroup: SqlBlock?, + child: ASTNode, + ): SqlBlock { + if (PsiTreeUtil.prevLeaf(child.psi)?.elementType == SqlTypes.WORD) { + return SqlFunctionParamBlock(child, sqlBlockFormattingCtx) + } + + when (lastGroup) { + is SqlKeywordGroupBlock -> { + // List-type test data for IN clause + NotQueryGroupUtil + .getSubGroup(lastGroup, child, sqlBlockFormattingCtx) + ?.let { return it } + + CreateTableUtil + .getCreateTableClauseSubGroup(lastGroup, child, sqlBlockFormattingCtx) + ?.let { return it } + + InsertClauseUtil + .getInsertClauseSubGroup(lastGroup, child, sqlBlockFormattingCtx) + ?.let { return it } + + UpdateClauseUtil + .getUpdateClauseSubGroup( + lastGroup, + child, + sqlBlockFormattingCtx, + )?.let { return it } + + if (lastGroup is SqlConditionKeywordGroupBlock) { + return SqlConditionalExpressionGroupBlock( + child, + sqlBlockFormattingCtx, + ) + } + + return SqlSubQueryGroupBlock(child, sqlBlockFormattingCtx) + } + + is SqlColumnDefinitionRawGroupBlock -> + return SqlDataTypeParamBlock(child, sqlBlockFormattingCtx) + + else -> + return SqlSubQueryGroupBlock(child, sqlBlockFormattingCtx) + } + } + + fun getCommaGroupBlock( + lastGroup: SqlBlock?, + child: ASTNode, + ): SqlBlock { + CreateTableUtil + .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) + } + } + + else -> SqlCommaBlock(child, sqlBlockFormattingCtx) + } + } + + fun getWordBlock( + lastGroup: SqlBlock?, + child: ASTNode, + ): SqlBlock = + when (lastGroup) { + is SqlKeywordGroupBlock -> { + when { + SqlKeywordUtil.isBeforeTableKeyword(lastGroup.getNodeText()) -> { + SqlTableBlock( + child, + sqlBlockFormattingCtx, + ) + } + + else -> SqlWordBlock(child, sqlBlockFormattingCtx) + } + } + + is SqlCreateTableColumnDefinitionGroupBlock -> { + // Top Column Definition Group Block + SqlCreateTableColumnDefinitionRawGroupBlock( + child, + sqlBlockFormattingCtx, + ) + } + + is SqlColumnDefinitionRawGroupBlock -> { + if (lastGroup.columnBlock == null) { + SqlColumnBlock( + child, + sqlBlockFormattingCtx, + ) + } else { + SqlWordBlock(child, sqlBlockFormattingCtx) + } + } + + else -> SqlWordBlock(child, sqlBlockFormattingCtx) + } + + fun getBlockCommentBlock( + child: ASTNode, + blockCommentSpacingBuilder: SqlCustomSpacingBuilder?, + ): SqlCommentBlock { + if (PsiTreeUtil.getChildOfType(child.psi, PsiComment::class.java) != null) { + return SqlBlockCommentBlock(child, sqlBlockFormattingCtx) + } + if (child.psi is SqlCustomElCommentExpr && + (child.psi as SqlCustomElCommentExpr).isConditionOrLoopDirective() + ) { + return SqlElConditionLoopCommentBlock( + child, + sqlBlockFormattingCtx, + blockCommentSpacingBuilder, + ) + } + return SqlElBlockCommentBlock( + child, + sqlBlockFormattingCtx, + blockCommentSpacingBuilder, + ) + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlKeywordUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlKeywordUtil.kt similarity index 85% rename from src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlKeywordUtil.kt rename to src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlKeywordUtil.kt index c809b9f3..851dd07d 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/SqlKeywordUtil.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlKeywordUtil.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 +package org.domaframework.doma.intellij.formatter.util enum class IndentType( private val level: Int, @@ -75,6 +75,8 @@ class SqlKeywordUtil { "truncate", "rename", "union", + "with", + "do", ) fun isTopKeyword(keyword: String): Boolean = TOP_KEYWORDS.contains(keyword.lowercase()) @@ -89,6 +91,7 @@ class SqlKeywordUtil { "having", "limit", "values", + "lateral", ) fun isSecondKeyword(keyword: String): Boolean = SECOND_KEYWORD.contains(keyword.lowercase()) @@ -100,6 +103,14 @@ class SqlKeywordUtil { "on", ) + private val CONDITION_KEYWORD = + setOf( + "and", + "or", + ) + + fun isConditionKeyword(keyword: String): Boolean = CONDITION_KEYWORD.contains(keyword.lowercase()) + fun isSecondOptionKeyword(keyword: String): Boolean = SECOND_OPTION_KEYWORD.contains(keyword.lowercase()) private val BEFORE_TABLE_KEYWORD = @@ -110,6 +121,17 @@ class SqlKeywordUtil { "table", ) + private val SELECT_SECOND_OPTION_KEYWORD = + setOf( + "from", + "where", + "group", + "having", + "order", + ) + + fun isSelectSecondOptionKeyword(keyword: String): Boolean = SELECT_SECOND_OPTION_KEYWORD.contains(keyword.lowercase()) + fun isBeforeTableKeyword(keyword: String): Boolean = BEFORE_TABLE_KEYWORD.contains(keyword.lowercase()) private val JOIN_KEYWORD = @@ -202,7 +224,6 @@ class SqlKeywordUtil { "unique", "primary", "foreign", - "constraint", ) fun isAttributeKeyword(keyword: String): Boolean = ATTRIBUTE_KEYWORD.contains(keyword.lowercase()) @@ -244,6 +265,14 @@ class SqlKeywordUtil { fun isOptionSqlKeyword(keyword: String): Boolean = OPTION_SQL_KEYWORDS.contains(keyword.lowercase()) + private val CONFLICT_ATTACHED_KEYWORDS = + setOf( + "conflict", + "constraint", + ) + + fun isConflictAttachedKeyword(keyword: String): Boolean = CONFLICT_ATTACHED_KEYWORDS.contains(keyword.lowercase()) + private val SET_LINE_KEYWORDS = mapOf( "into" to setOf("insert"), @@ -259,6 +288,10 @@ class SqlKeywordUtil { "by" to setOf("group", "order"), "and" to setOf("between"), "if" to setOf("table", "create"), + "conflict" to setOf("on"), + "nothing" to setOf("do"), + "constraint" to setOf("on"), + "update" to setOf("do"), ) fun isSetLineKeyword( @@ -266,12 +299,14 @@ class SqlKeywordUtil { prevKeyword: String, ): Boolean = SET_LINE_KEYWORDS[keyword.lowercase()]?.contains(prevKeyword.lowercase()) == true + fun isComma(keyword: String): Boolean = keyword == "," + fun getIndentType(keywordText: String): IndentType { val keyword = keywordText.lowercase() return when { isTopKeyword(keyword) -> IndentType.TOP - isSecondKeyword(keyword) -> IndentType.SECOND - isSecondOptionKeyword(keyword) -> IndentType.SECOND_OPTION + isSecondKeyword(keyword) || isSelectSecondOptionKeyword(keyword) -> IndentType.SECOND + isSecondOptionKeyword(keyword) || isConditionKeyword(keyword) -> IndentType.SECOND_OPTION isJoinKeyword(keyword) -> IndentType.JOIN isJoinAttachedKeyword(keyword) -> IndentType.JOIN isAttachedKeyword(keyword) -> IndentType.ATTACHED @@ -282,7 +317,8 @@ class SqlKeywordUtil { isLiteralKeyword(keyword) -> IndentType.LITERAL isOptionSqlKeyword(keyword) -> IndentType.OPTIONS isColumnTypeKeyword(keyword) -> IndentType.COLUMN - keyword == "," -> IndentType.COMMA + isConflictAttachedKeyword(keyword) -> IndentType.ATTACHED + isComma(keyword) -> IndentType.COMMA else -> IndentType.NONE } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/UpdateClauseUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/UpdateClauseUtil.kt new file mode 100644 index 00000000..9d435b84 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/UpdateClauseUtil.kt @@ -0,0 +1,42 @@ +/* + * 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.group.keyword.update.SqlUpdateColumnGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateSetGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlUpdateValueGroupBlock + +object UpdateClauseUtil { + fun getUpdateClauseSubGroup( + lastGroup: SqlBlock, + child: ASTNode, + sqlBlockFormattingCtx: SqlBlockFormattingContext, + ): SqlBlock? = + if (lastGroup is SqlUpdateSetGroupBlock) { + if (lastGroup.assignmentSymbol == null) { + SqlUpdateColumnGroupBlock(child, sqlBlockFormattingCtx) + } else if (lastGroup.columnDefinitionGroupBlock != null) { + SqlUpdateValueGroupBlock(child, sqlBlockFormattingCtx) + } else { + SqlSubQueryGroupBlock(child, sqlBlockFormattingCtx) + } + } else { + null + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/visitor/SqlFormatVisitor.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/visitor/SqlFormatVisitor.kt new file mode 100644 index 00000000..dac49b96 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/visitor/SqlFormatVisitor.kt @@ -0,0 +1,80 @@ +/* + * 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.visitor + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiRecursiveElementVisitor +import com.intellij.psi.PsiWhiteSpace +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.psi.util.elementType +import org.domaframework.doma.intellij.extension.expr.isConditionOrLoopDirective +import org.domaframework.doma.intellij.psi.SqlBlockComment +import org.domaframework.doma.intellij.psi.SqlCustomElCommentExpr +import org.domaframework.doma.intellij.psi.SqlTypes + +class SqlFormatVisitor : PsiRecursiveElementVisitor() { + val replaces = mutableListOf() + var lastElement: PsiElement? = null + + override fun visitElement(element: PsiElement) { + super.visitElement(element) + if (element !is PsiFile && element.nextSibling == null) { + lastElement = element + } + + if (PsiTreeUtil.getParentOfType(element, SqlBlockComment::class.java) == null) { + when (element.elementType) { + SqlTypes.KEYWORD, SqlTypes.COMMA, SqlTypes.LEFT_PAREN, SqlTypes.RIGHT_PAREN, SqlTypes.WORD -> { + replaces.add(element) + } + + SqlTypes.OTHER -> { + if (element.text == "=") { + val updateSetKeyword = + replaces + .lastOrNull { it.elementType == SqlTypes.KEYWORD } + if (updateSetKeyword?.text?.lowercase() == "set") { + replaces.add(element) + } + } + } + + SqlTypes.BLOCK_COMMENT -> + if ( + element is SqlCustomElCommentExpr && + element.isConditionOrLoopDirective() + ) { + replaces.add(element) + } + } + } + } + + override fun visitWhiteSpace(space: PsiWhiteSpace) { + super.visitWhiteSpace(space) + val nextElement = space.nextSibling + if (nextElement != null && + ( + space.text.contains("\n") || + nextElement.elementType == SqlTypes.LINE_COMMENT || + nextElement.elementType == SqlTypes.BLOCK_COMMENT + ) + ) { + replaces.add(space) + } + } +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 975b1d5b..b75e69e6 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -64,9 +64,9 @@ - - + implementationClass="org.domaframework.doma.intellij.formatter.builder.SqlFormattingModelBuilder"/> + +