Skip to content

Commit b6ad4c1

Browse files
authored
Merge pull request #404 from domaframework/fix/sql-format-in-group-line-breaks
Fix IN Clause Formatting
2 parents b0fc814 + cac0623 commit b6ad4c1

28 files changed

+536
-49
lines changed

src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlBlock.kt

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,9 @@ open class SqlBlock(
112112
*
113113
* @example
114114
* ```sql
115-
* WHERE
116-
* /*%if status == "pending" */
117-
* status = 'pending'
115+
* WHERE -- grand
116+
* /*%if status == "pending" */ -- parent
117+
* status = 'pending' -- child
118118
* ```
119119
*/
120120
protected fun isElementAfterConditionLoopDirective(): Boolean =
@@ -123,15 +123,27 @@ open class SqlBlock(
123123
(parent.parentBlock is SqlNewGroupBlock || parent.parentBlock is SqlElConditionLoopCommentBlock)
124124
} == true
125125

126+
protected fun isElementAfterConditionLoopEnd(): Boolean =
127+
(
128+
prevBlocks
129+
.lastOrNull()
130+
?.childBlocks
131+
?.firstOrNull() as? SqlElConditionLoopCommentBlock
132+
)?.conditionEnd != null
133+
126134
protected fun isFirstChildConditionLoopDirective(): Boolean = childBlocks.firstOrNull() is SqlElConditionLoopCommentBlock
127135

128136
fun getChildBlocksDropLast(
129137
dropIndex: Int = 1,
130138
skipCommentBlock: Boolean = true,
139+
skipConditionLoopCommentBlock: Boolean = true,
131140
): List<SqlBlock> {
132-
val children = childBlocks.dropLast(dropIndex)
141+
var children = childBlocks.dropLast(dropIndex)
133142
if (skipCommentBlock) {
134-
return children.filter { it !is SqlDefaultCommentBlock }
143+
children = children.filter { it !is SqlDefaultCommentBlock }
144+
}
145+
if (skipConditionLoopCommentBlock) {
146+
children = children.filter { it !is SqlElConditionLoopCommentBlock }
135147
}
136148
return children
137149
}
@@ -175,7 +187,8 @@ open class SqlBlock(
175187
private fun shouldSaveSpaceForConditionLoop(): Boolean =
176188
isConditionLoopDirectiveRegisteredBeforeParent() ||
177189
isElementAfterConditionLoopDirective() ||
178-
isFirstChildConditionLoopDirective()
190+
isFirstChildConditionLoopDirective() ||
191+
isElementAfterConditionLoopEnd()
179192

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

218+
protected fun getLastBlockHasConditionLoopDirective(): SqlElConditionLoopCommentBlock? =
219+
(prevBlocks.lastOrNull()?.childBlocks?.firstOrNull() as? SqlElConditionLoopCommentBlock)
220+
205221
/**
206222
* Creates the indentation length for the block.
207223
*

src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -248,14 +248,17 @@ class SqlElConditionLoopCommentBlock(
248248
is SqlKeywordGroupBlock -> {
249249
// 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.
250250
// Therefore, determine the position directly using the text offset.
251-
return if (parent.node.startOffset <
252-
node.startOffset
253-
) {
254-
// The child branch applies in cases where a conditional directive is included as a child of this block.
255-
val questOffset = if (parent is SqlWithQueryGroupBlock) 0 else 1
256-
parent.indent.groupIndentLen
257-
.plus(openConditionLoopDirectiveCount * 2)
258-
.plus(questOffset)
251+
return if (!isBeforeParentBlock()) {
252+
val lastBlockConditionLoopCommentBlock: SqlElConditionLoopCommentBlock? = getLastBlockHasConditionLoopDirective()
253+
if (lastBlockConditionLoopCommentBlock != null && lastBlockConditionLoopCommentBlock.conditionEnd != null) {
254+
lastBlockConditionLoopCommentBlock.indent.indentLen
255+
} else {
256+
// The child branch applies in cases where a conditional directive is included as a child of this block.
257+
val questOffset = if (parent is SqlWithQueryGroupBlock) 0 else 1
258+
parent.indent.groupIndentLen
259+
.plus(openConditionLoopDirectiveCount * 2)
260+
.plus(questOffset)
261+
}
259262
} else {
260263
parent.indent.indentLen.plus(openConditionLoopDirectiveCount * 2)
261264
}
@@ -285,4 +288,14 @@ class SqlElConditionLoopCommentBlock(
285288
val diffCount = startDirectives.minus(endDirectives)
286289
return if (diffCount > 0) diffCount.minus(1) else 0
287290
}
291+
292+
/**
293+
* Determine if this conditional loop directive block is positioned before its parent block.
294+
*/
295+
fun isBeforeParentBlock(): Boolean {
296+
parentBlock?.let { parent ->
297+
return parent.node.startOffset > node.startOffset
298+
}
299+
return false
300+
}
288301
}

src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlJoinGroupBlock.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import com.intellij.lang.ASTNode
1919
import com.intellij.psi.formatter.common.AbstractBlock
2020
import org.domaframework.doma.intellij.formatter.block.SqlBlock
2121
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
22+
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlLateralGroupBlock
2223
import org.domaframework.doma.intellij.formatter.util.IndentType
2324
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext
2425

src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/condition/SqlConditionKeywordGroupBlock.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword.condition
1818
import com.intellij.lang.ASTNode
1919
import org.domaframework.doma.intellij.formatter.block.SqlBlock
2020
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
21-
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlSecondOptionKeywordGroupBlock
21+
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlSecondOptionKeywordGroupBlock
2222
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock
2323
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext
2424

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright Doma Tools Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.domaframework.doma.intellij.formatter.block.group.keyword.option
17+
18+
import com.intellij.lang.ASTNode
19+
import org.domaframework.doma.intellij.formatter.block.SqlBlock
20+
import org.domaframework.doma.intellij.formatter.block.comment.SqlDefaultCommentBlock
21+
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
22+
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock
23+
import org.domaframework.doma.intellij.formatter.util.IndentType
24+
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext
25+
import org.domaframework.doma.intellij.psi.SqlTypes
26+
27+
class SqlInGroupBlock(
28+
node: ASTNode,
29+
context: SqlBlockFormattingContext,
30+
) : SqlKeywordGroupBlock(
31+
node,
32+
IndentType.OPTIONS,
33+
context,
34+
) {
35+
override fun setParentGroupBlock(lastGroup: SqlBlock?) {
36+
super.setParentGroupBlock(lastGroup)
37+
indent.indentLen = createBlockIndentLen()
38+
indent.groupIndentLen = createGroupIndentLen()
39+
}
40+
41+
override fun createBlockIndentLen(): Int {
42+
parentBlock?.let { parent ->
43+
if (parent is SqlElConditionLoopCommentBlock) return parent.indent.groupIndentLen
44+
val prevChildren = this.prevBlocks
45+
val children = prevChildren.filter { it !is SqlDefaultCommentBlock }
46+
val firstChild = children.firstOrNull()
47+
val sumChildren =
48+
if (firstChild is SqlElConditionLoopCommentBlock) {
49+
children.drop(1).dropLastWhile { it == this }
50+
} else {
51+
children
52+
}
53+
54+
val dotCount = sumChildren.count { it.node.elementType == SqlTypes.DOT }
55+
return sumChildren
56+
.sumOf { prev ->
57+
prev
58+
.getChildrenTextLen()
59+
.plus(prev.getNodeText().length.plus(1))
60+
}.minus(dotCount * 2)
61+
.plus(parent.indent.groupIndentLen)
62+
.plus(1)
63+
}
64+
return 0
65+
}
66+
67+
override fun createGroupIndentLen(): Int = indent.indentLen.plus(getNodeText().length)
68+
69+
override fun isSaveSpace(lastGroup: SqlBlock?): Boolean {
70+
if (lastGroup is SqlElConditionLoopCommentBlock) {
71+
if (lastGroup.conditionType.isElse()) return false
72+
return !lastGroup.isBeforeParentBlock()
73+
}
74+
return false
75+
}
76+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package org.domaframework.doma.intellij.formatter.block.group.keyword
16+
package org.domaframework.doma.intellij.formatter.block.group.keyword.option
1717

1818
import com.intellij.lang.ASTNode
1919
import org.domaframework.doma.intellij.formatter.block.SqlBlock
2020
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
21+
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock
2122
import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlFromGroupBlock
2223
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock
2324
import org.domaframework.doma.intellij.formatter.util.IndentType
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package org.domaframework.doma.intellij.formatter.block.group.keyword
16+
package org.domaframework.doma.intellij.formatter.block.group.keyword.option
1717

1818
import com.intellij.lang.ASTNode
1919
import org.domaframework.doma.intellij.formatter.block.SqlBlock
2020
import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock
2121
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
22+
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock
2223
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock
2324
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock
2425
import org.domaframework.doma.intellij.formatter.util.IndentType
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright Doma Tools Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.domaframework.doma.intellij.formatter.block.group.keyword.second
17+
18+
import com.intellij.lang.ASTNode
19+
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext
20+
21+
class SqlWhereGroupBlock(
22+
node: ASTNode,
23+
context: SqlBlockFormattingContext,
24+
) : SqlSecondKeywordBlock(node, context) {
25+
override fun createGroupIndentLen(): Int = indent.indentLen.plus(getNodeText().length)
26+
}

src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlJoinQueriesGroupBlock.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword.top
1717

1818
import com.intellij.lang.ASTNode
1919
import org.domaframework.doma.intellij.formatter.block.SqlBlock
20+
import org.domaframework.doma.intellij.formatter.block.SqlFileBlock
2021
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
2122
import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithQuerySubGroupBlock
2223
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext
@@ -41,8 +42,8 @@ class SqlJoinQueriesGroupBlock(
4142
override fun createBlockIndentLen(): Int {
4243
parentBlock?.let { parent ->
4344
return when (parent) {
44-
is SqlWithQuerySubGroupBlock,
45-
-> parent.indent.groupIndentLen
45+
is SqlFileBlock -> 0
46+
is SqlWithQuerySubGroupBlock -> parent.indent.groupIndentLen
4647
is SqlElConditionLoopCommentBlock -> createIndentLenInConditionLoopDirective(parent)
4748
else -> parent.indent.groupIndentLen.plus(1)
4849
}

src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/top/SqlTopQueryGroupBlock.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ abstract class SqlTopQueryGroupBlock(
4141
SqlWithQuerySubGroupBlock::class,
4242
SqlElConditionLoopCommentBlock::class,
4343
)
44-
private val offset = 0
44+
private const val OFFSET = 0
4545
}
4646

4747
override fun setParentGroupBlock(lastGroup: SqlBlock?) {
@@ -55,7 +55,7 @@ abstract class SqlTopQueryGroupBlock(
5555

5656
override fun createBlockIndentLen(): Int {
5757
parentBlock?.let { parent ->
58-
if (parent.indent.indentLevel == IndentType.FILE) return offset
58+
if (parent.indent.indentLevel == IndentType.FILE) return OFFSET
5959
if (parent is SqlElConditionLoopCommentBlock) {
6060
return createIndentLenInConditionLoopDirective(parent)
6161
}
@@ -84,7 +84,7 @@ abstract class SqlTopQueryGroupBlock(
8484
// align with the indent of that parent's parent
8585
prevGroupBlock?.let { prev ->
8686
if (prev.indent.indentLevel >= indent.indentLevel) {
87-
p.indent.indentLen = prev.parentBlock?.indent?.indentLen ?: offset
87+
p.indent.indentLen = prev.parentBlock?.indent?.indentLen ?: OFFSET
8888
}
8989
}
9090
} else {

0 commit comments

Comments
 (0)