Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ open class SqlBlock(
*
* @example
* ```sql
* WHERE
* /*%if status == "pending" */
* status = 'pending'
* WHERE -- grand
* /*%if status == "pending" */ -- parent
* status = 'pending' -- child
* ```
*/
protected fun isElementAfterConditionLoopDirective(): Boolean =
Expand All @@ -123,15 +123,27 @@ open class SqlBlock(
(parent.parentBlock is SqlNewGroupBlock || parent.parentBlock is SqlElConditionLoopCommentBlock)
} == true

protected fun isElementAfterConditionLoopEnd(): Boolean =
(
prevBlocks
.lastOrNull()
?.childBlocks
?.firstOrNull() as? SqlElConditionLoopCommentBlock
)?.conditionEnd != null

protected fun isFirstChildConditionLoopDirective(): Boolean = childBlocks.firstOrNull() is SqlElConditionLoopCommentBlock

fun getChildBlocksDropLast(
dropIndex: Int = 1,
skipCommentBlock: Boolean = true,
skipConditionLoopCommentBlock: Boolean = true,
): List<SqlBlock> {
val children = childBlocks.dropLast(dropIndex)
var children = childBlocks.dropLast(dropIndex)
if (skipCommentBlock) {
return children.filter { it !is SqlDefaultCommentBlock }
children = children.filter { it !is SqlDefaultCommentBlock }
}
if (skipConditionLoopCommentBlock) {
children = children.filter { it !is SqlElConditionLoopCommentBlock }
}
return children
}
Expand Down Expand Up @@ -175,7 +187,8 @@ open class SqlBlock(
private fun shouldSaveSpaceForConditionLoop(): Boolean =
isConditionLoopDirectiveRegisteredBeforeParent() ||
isElementAfterConditionLoopDirective() ||
isFirstChildConditionLoopDirective()
isFirstChildConditionLoopDirective() ||
isElementAfterConditionLoopEnd()

private fun shouldSaveSpaceForNewGroup(parent: SqlNewGroupBlock): Boolean {
val prevWord = prevBlocks.lastOrNull { it !is SqlCommentBlock }
Expand All @@ -202,6 +215,9 @@ open class SqlBlock(
lastPrevBlock.node.psi.startOffset > parent.node.psi.startOffset
}

protected fun getLastBlockHasConditionLoopDirective(): SqlElConditionLoopCommentBlock? =
(prevBlocks.lastOrNull()?.childBlocks?.firstOrNull() as? SqlElConditionLoopCommentBlock)

/**
* Creates the indentation length for the block.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package org.domaframework.doma.intellij.formatter.block

import com.intellij.lang.ASTNode
import com.intellij.psi.formatter.common.AbstractBlock
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
import org.domaframework.doma.intellij.formatter.block.conflict.SqlDoGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock
Expand Down Expand Up @@ -96,13 +95,7 @@ open class SqlKeywordBlock(
}

else -> {
parentBlock?.let { parent ->
if (parent is SqlElConditionLoopCommentBlock) {
parent.indent.groupIndentLen
} else {
1
}
} ?: 1
parentBlock?.indent?.groupIndentLen ?: 1
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ class SqlElConditionLoopCommentBlock(
}

companion object {
private const val DIRECTIVE_INDENT_STEP = 2
private const val DEFAULT_INDENT_OFFSET = 1

private val LINE_BREAK_PARENT_TYPES =
listOf(
SqlSubGroupBlock::class,
Expand Down Expand Up @@ -121,7 +124,7 @@ class SqlElConditionLoopCommentBlock(
childBlocks.forEach { child ->
if (child is SqlElConditionLoopCommentBlock && child.conditionType.isStartDirective()) {
// If the child is a condition loop directive, align its indentation with the parent directive
child.indent.indentLen = indent.indentLen.plus(2)
child.indent.indentLen = indent.indentLen.plus(DIRECTIVE_INDENT_STEP)
} else if (child is SqlLineCommentBlock) {
if (PsiTreeUtil.prevLeaf(child.node.psi, false)?.text?.contains(StringUtil.LINE_SEPARATE) == true) {
child.indent.indentLen = indent.groupIndentLen
Expand Down Expand Up @@ -201,37 +204,7 @@ class SqlElConditionLoopCommentBlock(
}
val openConditionLoopDirectiveCount = getOpenDirectiveCount(parent)
when (parent) {
is SqlSubGroupBlock -> {
val parentGroupIndentLen = parent.indent.groupIndentLen
val grand = parent.parentBlock
grand?.let { grand ->
if (grand is SqlCreateKeywordGroupBlock) {
val grandIndentLen = grand.indent.groupIndentLen
return grandIndentLen.plus(parentGroupIndentLen).minus(1)
}
if (grand is SqlInsertQueryGroupBlock) {
return parentGroupIndentLen
}
if (grand is SqlColumnRawGroupBlock) {
val grandIndentLen = grand.indent.groupIndentLen
var prevTextLen = 1
parent.prevChildren?.dropLast(1)?.forEach { prev ->
prevTextLen = prevTextLen.plus(prev.getNodeText().length)
}
return grandIndentLen.plus(prevTextLen)
}
}
return if (TypeUtil.isExpectedClassType(
SqlRightPatternBlock.NOT_INDENT_EXPECTED_TYPES,
parent,
) ||
parent is SqlWithCommonTableGroupBlock
) {
parentGroupIndentLen.plus(openConditionLoopDirectiveCount * 2)
} else {
parentGroupIndentLen.plus(openConditionLoopDirectiveCount * 2).plus(1)
}
}
is SqlSubGroupBlock -> return calculateSubGroupBlockIndent(parent, openConditionLoopDirectiveCount)

is SqlElConditionLoopCommentBlock -> {
if (conditionType.isEnd()) {
Expand All @@ -241,26 +214,29 @@ class SqlElConditionLoopCommentBlock(
} else if (conditionType.isElse()) {
return parent.indent.indentLen
} else {
return parent.indent.indentLen.plus(2)
return parent.indent.indentLen.plus(DIRECTIVE_INDENT_STEP)
}
}

is SqlKeywordGroupBlock -> {
// At this point, it's not possible to determine whether the parent keyword group appears before or after this block based solely on the parent-child relationship.
// Therefore, determine the position directly using the text offset.
return if (parent.node.startOffset <
node.startOffset
) {
// The child branch applies in cases where a conditional directive is included as a child of this block.
val questOffset = if (parent is SqlWithQueryGroupBlock) 0 else 1
parent.indent.groupIndentLen
.plus(openConditionLoopDirectiveCount * 2)
.plus(questOffset)
return if (!isBeforeParentBlock()) {
val lastBlockConditionLoopCommentBlock: SqlElConditionLoopCommentBlock? = getLastBlockHasConditionLoopDirective()
if (lastBlockConditionLoopCommentBlock != null && lastBlockConditionLoopCommentBlock.conditionEnd != null) {
lastBlockConditionLoopCommentBlock.indent.indentLen
} else {
// The child branch applies in cases where a conditional directive is included as a child of this block.
val questOffset = if (parent is SqlWithQueryGroupBlock) 0 else 1
parent.indent.groupIndentLen
.plus(openConditionLoopDirectiveCount * DIRECTIVE_INDENT_STEP)
.plus(questOffset)
}
} else {
parent.indent.indentLen.plus(openConditionLoopDirectiveCount * 2)
parent.indent.indentLen.plus(openConditionLoopDirectiveCount * DIRECTIVE_INDENT_STEP)
}
}
else -> return parent.indent.indentLen.plus(openConditionLoopDirectiveCount * 2)
else -> return parent.indent.indentLen.plus(openConditionLoopDirectiveCount * DIRECTIVE_INDENT_STEP)
}
}
return 0
Expand All @@ -285,4 +261,57 @@ class SqlElConditionLoopCommentBlock(
val diffCount = startDirectives.minus(endDirectives)
return if (diffCount > 0) diffCount.minus(1) else 0
}

/**
* Determine if this conditional loop directive block is positioned before its parent block.
*/
fun isBeforeParentBlock(): Boolean {
parentBlock?.let { parent ->
return parent.node.startOffset > node.startOffset
}
return false
}

fun checkConditionLoopDirectiveParentBlock(block: SqlBlock): Boolean = isBeforeParentBlock() && parentBlock == block

private fun calculateSubGroupBlockIndent(
parent: SqlSubGroupBlock,
openDirectiveCount: Int,
): Int {
val parentGroupIndentLen = parent.indent.groupIndentLen
val grand = parent.parentBlock

grand?.let { grandParent ->
when (grandParent) {
is SqlCreateKeywordGroupBlock -> {
val grandIndentLen = grandParent.indent.groupIndentLen
return grandIndentLen.plus(parentGroupIndentLen).minus(DEFAULT_INDENT_OFFSET)
}
is SqlInsertQueryGroupBlock -> return parentGroupIndentLen
is SqlColumnRawGroupBlock -> {
val grandIndentLen = grandParent.indent.groupIndentLen
val prevTextLen = calculatePreviousTextLength(parent)
return grandIndentLen.plus(prevTextLen)
}
}
}

return if (shouldNotIndent(parent)) {
parentGroupIndentLen.plus(openDirectiveCount * DIRECTIVE_INDENT_STEP)
} else {
parentGroupIndentLen.plus(openDirectiveCount * DIRECTIVE_INDENT_STEP).plus(DEFAULT_INDENT_OFFSET)
}
}

private fun calculatePreviousTextLength(parent: SqlSubGroupBlock): Int {
var prevTextLen = DEFAULT_INDENT_OFFSET
parent.prevChildren?.dropLast(1)?.forEach { prev ->
prevTextLen = prevTextLen.plus(prev.getNodeText().length)
}
return prevTextLen
}

private fun shouldNotIndent(parent: SqlSubGroupBlock): Boolean =
TypeUtil.isExpectedClassType(SqlRightPatternBlock.NOT_INDENT_EXPECTED_TYPES, parent) ||
parent is SqlWithCommonTableGroupBlock
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import com.intellij.lang.ASTNode
import com.intellij.psi.formatter.common.AbstractBlock
import org.domaframework.doma.intellij.formatter.block.SqlBlock
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlLateralGroupBlock
import org.domaframework.doma.intellij.formatter.util.IndentType
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword.condition
import com.intellij.lang.ASTNode
import org.domaframework.doma.intellij.formatter.block.SqlBlock
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlSecondOptionKeywordGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlSecondOptionKeywordGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* 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.option

import com.intellij.lang.ASTNode
import org.domaframework.doma.intellij.formatter.block.SqlBlock
import org.domaframework.doma.intellij.formatter.block.comment.SqlDefaultCommentBlock
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock
import org.domaframework.doma.intellij.formatter.util.IndentType
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext
import org.domaframework.doma.intellij.psi.SqlTypes

class SqlInGroupBlock(
node: ASTNode,
context: SqlBlockFormattingContext,
) : SqlKeywordGroupBlock(
node,
IndentType.OPTIONS,
context,
) {
override fun setParentGroupBlock(lastGroup: SqlBlock?) {
super.setParentGroupBlock(lastGroup)
indent.indentLen = createBlockIndentLen()
indent.groupIndentLen = createGroupIndentLen()
}

override fun createBlockIndentLen(): Int {
parentBlock?.let { parent ->
if (parent is SqlElConditionLoopCommentBlock) return parent.indent.groupIndentLen
val prevChildren = this.prevBlocks
val children = prevChildren.filter { it !is SqlDefaultCommentBlock }
val firstChild = children.firstOrNull()
val sumChildren =
if (firstChild is SqlElConditionLoopCommentBlock) {
children.drop(1).dropLastWhile { it == this }
} else {
children
}

val dotCount = sumChildren.count { it.node.elementType == SqlTypes.DOT }
return sumChildren
.sumOf { prev ->
prev
.getChildrenTextLen()
.plus(prev.getNodeText().length.plus(1))
}.minus(dotCount * 2)
.plus(parent.indent.groupIndentLen)
.plus(1)
}
return 0
}

override fun createGroupIndentLen(): Int = indent.indentLen.plus(getNodeText().length)

override fun isSaveSpace(lastGroup: SqlBlock?): Boolean {
if (lastGroup is SqlElConditionLoopCommentBlock) {
return if (lastGroup.conditionType.isElse()) {
false
} else {
!lastGroup.isBeforeParentBlock()
}
}
return false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
* 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.option

import com.intellij.lang.ASTNode
import org.domaframework.doma.intellij.formatter.block.SqlBlock
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlFromGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock
import org.domaframework.doma.intellij.formatter.util.IndentType
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
* 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.option

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.comment.SqlElConditionLoopCommentBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock
import org.domaframework.doma.intellij.formatter.util.IndentType
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* 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.second

import com.intellij.lang.ASTNode
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext

class SqlWhereGroupBlock(
node: ASTNode,
context: SqlBlockFormattingContext,
) : SqlSecondKeywordBlock(node, context) {
override fun createGroupIndentLen(): Int = indent.indentLen.plus(getNodeText().length)
}
Loading
Loading