Skip to content

Commit a3cddd7

Browse files
committed
Add a method to validate the parent-child relationship with SqlElConditionLoopCommentBlock and determine whether the block should be line-broken.
1 parent 1bc662e commit a3cddd7

File tree

6 files changed

+121
-38
lines changed

6 files changed

+121
-38
lines changed

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

Lines changed: 64 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,13 @@ open class SqlBlock(
5050
var indentLevel: IndentType,
5151
/**
5252
* The number of indentation spaces for this element.
53+
*
5354
* Returns `0` if there is no line break.
5455
*/
5556
var indentLen: Int,
5657
/**
5758
* Indentation baseline applied to the group itself.
59+
*
5860
* Even if the group does not start on a new line,
5961
* it determines and applies indentation to the group based on factors such as the number of preceding characters.
6062
*/
@@ -81,6 +83,48 @@ open class SqlBlock(
8183

8284
private fun isExcludedFromTextLength(block: SqlBlock): Boolean = block.node.elementType in setOf(SqlTypes.DOT, SqlTypes.RIGHT_PAREN)
8385

86+
/**
87+
* Checks if a conditional loop directive is registered before the parent block.
88+
*
89+
* @note
90+
* If the next element after a conditional directive is not a conditional directive block,
91+
* the directive becomes a child of the next element block.
92+
* Therefore, if the first element in [childBlocks] is a conditional directive,
93+
* it can be determined that—syntactically—the conditional directive was placed immediately before the current block.
94+
*/
95+
protected fun isConditionLoopDirectiveRegisteredBeforeParent(): Boolean {
96+
val firstPrevBlock = (prevBlocks.lastOrNull() as? SqlElConditionLoopCommentBlock)
97+
parentBlock?.let { parent ->
98+
return firstPrevBlock != null &&
99+
firstPrevBlock.conditionEnd != null &&
100+
firstPrevBlock.node.startOffset > parent.node.startOffset
101+
}
102+
return false
103+
}
104+
105+
/**
106+
* Determines if this is the element immediately after a conditional loop directive.
107+
*
108+
* @note
109+
* The parent conditional loop directive becomes a child of the element immediately after the conditional loop directive.
110+
* In the following case, "%if" is a child of "status", and the following "=" and "'pending'" are children of "%if".
111+
* Therefore, set the condition to break line only when the parent of the conditional loop directive is a group block.
112+
*
113+
* @example
114+
* ```sql
115+
* WHERE
116+
* /*%if status == "pending" */
117+
* status = 'pending'
118+
* ```
119+
*/
120+
protected fun isElementAfterConditionLoopDirective(): Boolean =
121+
(parentBlock as? SqlElConditionLoopCommentBlock)?.let { parent ->
122+
parent.childBlocks.firstOrNull() == this &&
123+
(parent.parentBlock is SqlNewGroupBlock || parent.parentBlock is SqlElConditionLoopCommentBlock)
124+
} == true
125+
126+
protected fun isFirstChildConditionLoopDirective(): Boolean = childBlocks.firstOrNull() is SqlElConditionLoopCommentBlock
127+
84128
fun getChildBlocksDropLast(
85129
dropIndex: Int = 1,
86130
skipCommentBlock: Boolean = true,
@@ -121,31 +165,17 @@ open class SqlBlock(
121165
fun isEnableFormat(): Boolean = enableFormat
122166

123167
open fun isSaveSpace(lastGroup: SqlBlock?): Boolean =
124-
parentBlock?.let { parent ->
125-
when (parent) {
126-
is SqlElConditionLoopCommentBlock -> shouldSaveSpaceForConditionLoop(parent)
127-
is SqlNewGroupBlock -> shouldSaveSpaceForNewGroup(parent)
128-
else -> false
168+
when (lastGroup) {
169+
is SqlNewGroupBlock -> shouldSaveSpaceForNewGroup(lastGroup)
170+
else -> {
171+
shouldSaveSpaceForConditionLoop()
129172
}
130173
} == true
131174

132-
private fun shouldSaveSpaceForConditionLoop(parent: SqlElConditionLoopCommentBlock): Boolean {
133-
val prevBlock = prevBlocks.lastOrNull { it !is SqlDefaultCommentBlock }
134-
val isPrevBlockElseOrEnd =
135-
prevBlock is SqlElConditionLoopCommentBlock &&
136-
(prevBlock.conditionType.isElse() || prevBlock.conditionType.isEnd())
137-
val hasNoChildrenExceptLast = parent.childBlocks.dropLast(1).isEmpty()
138-
if (parent.conditionType.isElse()) {
139-
return prevBlocks.isEmpty()
140-
}
141-
142-
val isConditionDirectiveParentGroup =
143-
parent.parentBlock?.let { grand ->
144-
grand is SqlNewGroupBlock
145-
} == true
146-
147-
return isPrevBlockElseOrEnd || (hasNoChildrenExceptLast && isConditionDirectiveParentGroup)
148-
}
175+
private fun shouldSaveSpaceForConditionLoop(): Boolean =
176+
isConditionLoopDirectiveRegisteredBeforeParent() ||
177+
isElementAfterConditionLoopDirective() ||
178+
isFirstChildConditionLoopDirective()
149179

150180
private fun shouldSaveSpaceForNewGroup(parent: SqlNewGroupBlock): Boolean {
151181
val prevWord = prevBlocks.lastOrNull { it !is SqlCommentBlock }
@@ -174,6 +204,8 @@ open class SqlBlock(
174204

175205
/**
176206
* Creates the indentation length for the block.
207+
*
208+
* @return The number of spaces to use for indentation
177209
*/
178210
open fun createBlockIndentLen(): Int = 0
179211

@@ -183,18 +215,24 @@ open class SqlBlock(
183215

184216
/**
185217
* Creates a spacing builder for custom spacing rules.
218+
*
219+
* @return A new instance of SqlCustomSpacingBuilder
186220
*/
187221
protected open fun createSpacingBuilder(): SqlCustomSpacingBuilder = SqlCustomSpacingBuilder()
188222

189223
override fun buildChildren(): List<Block?>? = emptyList()
190224

191225
/**
192226
* Determines whether to adjust the indentation on pressing Enter.
227+
*
228+
* @return true if indentation should be adjusted on Enter, false otherwise
193229
*/
194230
fun isAdjustIndentOnEnter(): Boolean = formatMode == FormattingMode.ADJUST_INDENT_ON_ENTER && !isEnableFormat()
195231

196232
/**
197233
* Returns the indentation for the block.
234+
*
235+
* @return The indent to apply to this block, or null if no indentation should be applied
198236
*/
199237
override fun getIndent(): Indent? =
200238
if (isAdjustIndentOnEnter()) {
@@ -210,6 +248,8 @@ open class SqlBlock(
210248

211249
/**
212250
* Returns the child indentation for the block.
251+
*
252+
* @return The indent to apply to child blocks
213253
*/
214254
override fun getChildIndent(): Indent? =
215255
if (isEnableFormat()) {
@@ -224,6 +264,8 @@ open class SqlBlock(
224264

225265
/**
226266
* Determines whether the block is a leaf node.
267+
*
268+
* @return true if this block has no child nodes, false otherwise
227269
*/
228270
override fun isLeaf(): Boolean = myNode.firstChildNode == null
229271
}

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

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import org.domaframework.doma.intellij.formatter.block.expr.SqlElFieldAccessBloc
2929
import org.domaframework.doma.intellij.formatter.block.expr.SqlElFunctionCallBlock
3030
import org.domaframework.doma.intellij.formatter.block.expr.SqlElStaticFieldAccessBlock
3131
import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlValuesGroupBlock
32+
import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithQuerySubGroupBlock
3233
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock
3334
import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder
3435
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext
@@ -176,7 +177,11 @@ open class SqlElBlockCommentBlock(
176177
is SqlElConditionLoopCommentBlock -> parent.indent.groupIndentLen
177178
is SqlSubQueryGroupBlock -> {
178179
if (parent.getChildBlocksDropLast().isEmpty()) {
179-
0
180+
if (isConditionLoopDirectiveRegisteredBeforeParent()) {
181+
parent.indent.groupIndentLen
182+
} else {
183+
parent.indent.groupIndentLen
184+
}
180185
} else if (parent.isFirstLineComment) {
181186
parent.indent.groupIndentLen.minus(2)
182187
} else {
@@ -192,10 +197,16 @@ open class SqlElBlockCommentBlock(
192197

193198
override fun isSaveSpace(lastGroup: SqlBlock?): Boolean =
194199
parentBlock?.let { parent ->
195-
(
196-
parent is SqlValuesGroupBlock ||
197-
parent is SqlElConditionLoopCommentBlock
198-
) &&
199-
parent.childBlocks.dropLast(1).isEmpty()
200+
isConditionLoopDirectiveRegisteredBeforeParent() ||
201+
(
202+
(
203+
parent is SqlWithQuerySubGroupBlock ||
204+
parent is SqlValuesGroupBlock ||
205+
parent is SqlElConditionLoopCommentBlock
206+
) &&
207+
parent.childBlocks
208+
.dropLast(1)
209+
.none { it !is SqlElConditionLoopCommentBlock }
210+
)
200211
} == true
201212
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnRaw
3636
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock
3737
import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateKeywordGroupBlock
3838
import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertQueryGroupBlock
39+
import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithCommonTableGroupBlock
40+
import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithQueryGroupBlock
3941
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock
4042
import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder
4143
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ package org.domaframework.doma.intellij.formatter.block.group.keyword.top
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
2221
import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithQuerySubGroupBlock
23-
import org.domaframework.doma.intellij.formatter.util.IndentType
2422
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext
2523

2624
/**
@@ -30,9 +28,9 @@ import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext
3028
class SqlJoinQueriesGroupBlock(
3129
node: ASTNode,
3230
context: SqlBlockFormattingContext,
33-
) : SqlKeywordGroupBlock(node, IndentType.TOP, context) {
31+
) : SqlTopQueryGroupBlock(node, context) {
3432
// TODO Customize offset
35-
val offset = 0
33+
private val offset = 0
3634

3735
override fun setParentGroupBlock(lastGroup: SqlBlock?) {
3836
super.setParentGroupBlock(lastGroup)
@@ -43,8 +41,9 @@ class SqlJoinQueriesGroupBlock(
4341
override fun createBlockIndentLen(): Int {
4442
parentBlock?.let { parent ->
4543
return when (parent) {
46-
is SqlWithQuerySubGroupBlock, is SqlElConditionLoopCommentBlock,
44+
is SqlWithQuerySubGroupBlock,
4745
-> parent.indent.groupIndentLen
46+
is SqlElConditionLoopCommentBlock -> createIndentLenInConditionLoopDirective(parent)
4847
else -> parent.indent.groupIndentLen.plus(1)
4948
}
5049
}

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

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import com.intellij.lang.ASTNode
1919
import org.domaframework.doma.intellij.common.util.TypeUtil
2020
import org.domaframework.doma.intellij.formatter.block.SqlBlock
2121
import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock
22+
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
23+
import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlValuesGroupBlock
2224
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock
2325
import org.domaframework.doma.intellij.formatter.block.word.SqlWordBlock
2426
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext
@@ -71,14 +73,34 @@ class SqlWithCommonTableGroupBlock(
7173
}
7274
}
7375

74-
override fun createBlockIndentLen(): Int = 0
76+
override fun createBlockIndentLen(): Int {
77+
parentBlock?.let { parent ->
78+
val prevBlock =
79+
parent
80+
.getChildBlocksDropLast()
81+
.lastOrNull()
82+
return if (prevBlock is SqlElConditionLoopCommentBlock) 4 else 0
83+
}
84+
return 0
85+
}
7586

7687
override fun createGroupIndentLen(): Int {
7788
parentBlock?.let { parent ->
78-
getChildBlocksDropLast().sumOf { it.getNodeText().length.plus(1) }
89+
return getChildBlocksDropLast().sumOf { it.getNodeText().length.plus(1) }.plus(offset)
7990
}
8091
return offset
8192
}
8293

83-
override fun isSaveSpace(lastGroup: SqlBlock?): Boolean = !isFirstTable
94+
override fun isSaveSpace(lastGroup: SqlBlock?): Boolean =
95+
parentBlock?.let { parent ->
96+
isFirstChildConditionLoopDirective() ||
97+
(
98+
(
99+
parent is SqlValuesGroupBlock ||
100+
parent is SqlElConditionLoopCommentBlock
101+
) &&
102+
parent.childBlocks.dropLast(1).isEmpty()
103+
)
104+
} == true ||
105+
!isFirstTable
84106
}

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,15 @@ class SqlWithQueryGroupBlock(
4848

4949
override fun createBlockIndentLen(): Int = 0
5050

51-
override fun createGroupIndentLen(): Int =
52-
childBlocks
51+
override fun createGroupIndentLen(): Int {
52+
val sumChildren =
53+
if (isConditionLoopDirectiveRegisteredBeforeParent()) {
54+
childBlocks.drop(1)
55+
} else {
56+
childBlocks
57+
}
58+
return sumChildren
5359
.sumOf { it.getNodeText().length.plus(1) }
5460
.plus(getNodeText().length)
61+
}
5562
}

0 commit comments

Comments
 (0)