Skip to content

Commit 514d571

Browse files
committed
Refactoring
1 parent f70c6cd commit 514d571

File tree

6 files changed

+280
-207
lines changed

6 files changed

+280
-207
lines changed

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

Lines changed: 56 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -65,23 +65,19 @@ open class SqlBlock(
6565
open val childBlocks = mutableListOf<SqlBlock>()
6666
open var prevBlocks = emptyList<SqlBlock>()
6767

68-
fun getChildrenTextLen(): Int =
69-
childBlocks.sumOf { child ->
70-
val children =
71-
child.childBlocks.filter { it !is SqlDefaultCommentBlock }
72-
if (children.isNotEmpty()) {
73-
child
74-
.getChildrenTextLen()
75-
.plus(child.getNodeText().length)
76-
} else if (child.node.elementType == SqlTypes.DOT ||
77-
child.node.elementType == SqlTypes.RIGHT_PAREN
78-
) {
79-
// Since elements do not include surrounding spaces, they should be excluded from the character count.
80-
0
81-
} else {
82-
child.getNodeText().length.plus(1)
83-
}
68+
fun getChildrenTextLen(): Int = childBlocks.sumOf { child -> calculateChildTextLength(child) }
69+
70+
private fun calculateChildTextLength(child: SqlBlock): Int {
71+
val nonCommentChildren = child.childBlocks.filterNot { it is SqlDefaultCommentBlock }
72+
73+
return when {
74+
nonCommentChildren.isNotEmpty() -> child.getChildrenTextLen() + child.getNodeText().length
75+
isExcludedFromTextLength(child) -> 0
76+
else -> child.getNodeText().length + 1
8477
}
78+
}
79+
80+
private fun isExcludedFromTextLength(block: SqlBlock): Boolean = block.node.elementType in setOf(SqlTypes.DOT, SqlTypes.RIGHT_PAREN)
8581

8682
fun getChildBlocksDropLast(
8783
dropIndex: Int = 1,
@@ -122,34 +118,48 @@ open class SqlBlock(
122118

123119
fun isEnableFormat(): Boolean = enableFormat
124120

125-
open fun isSaveSpace(lastGroup: SqlBlock?): Boolean {
121+
open fun isSaveSpace(lastGroup: SqlBlock?): Boolean =
126122
parentBlock?.let { parent ->
127-
if (parent is SqlElConditionLoopCommentBlock) {
128-
val prevBlock =
129-
prevBlocks.lastOrNull { it !is SqlDefaultCommentBlock }
130-
return prevBlock is SqlElConditionLoopCommentBlock &&
131-
(prevBlock.conditionType.isElse() || prevBlock.conditionType.isEnd()) ||
132-
parent.childBlocks.dropLast(1).isEmpty()
133-
}
134-
// Checks for non-breaking keyword combinations, ignoring comment blocks
135-
if (parent is SqlNewGroupBlock) {
136-
val prevWord = prevBlocks.lastOrNull { it !is SqlCommentBlock }
137-
if (SqlKeywordUtil.isSetLineKeyword(getNodeText(), parent.getNodeText()) ||
138-
SqlKeywordUtil.isSetLineKeyword(getNodeText(), prevWord?.getNodeText() ?: "")
139-
) {
140-
return false
141-
}
142-
// Breaks a line if it is a child of itself or preceded by a condition/loop directive
143-
return childBlocks.lastOrNull() is SqlElConditionLoopCommentBlock ||
144-
(
145-
prevBlocks.lastOrNull() is SqlElConditionLoopCommentBlock &&
146-
prevBlocks
147-
.last()
148-
.node.psi.startOffset > parent.node.psi.startOffset
149-
)
123+
when (parent) {
124+
is SqlElConditionLoopCommentBlock -> shouldSaveSpaceForConditionLoop(parent)
125+
is SqlNewGroupBlock -> shouldSaveSpaceForNewGroup(parent)
126+
else -> false
150127
}
128+
} ?: false
129+
130+
private fun shouldSaveSpaceForConditionLoop(parent: SqlElConditionLoopCommentBlock): Boolean {
131+
val prevBlock = prevBlocks.lastOrNull { it !is SqlDefaultCommentBlock }
132+
val isPrevBlockElseOrEnd =
133+
prevBlock is SqlElConditionLoopCommentBlock &&
134+
(prevBlock.conditionType.isElse() || prevBlock.conditionType.isEnd())
135+
val hasNoChildrenExceptLast = parent.childBlocks.dropLast(1).isEmpty()
136+
137+
return isPrevBlockElseOrEnd || hasNoChildrenExceptLast
138+
}
139+
140+
private fun shouldSaveSpaceForNewGroup(parent: SqlNewGroupBlock): Boolean {
141+
val prevWord = prevBlocks.lastOrNull { it !is SqlCommentBlock }
142+
143+
if (isNonBreakingKeywordCombination(parent, prevWord)) {
144+
return false
151145
}
152-
return false
146+
147+
return isFollowedByConditionLoop() || isPrecededByConditionLoop(parent)
148+
}
149+
150+
private fun isNonBreakingKeywordCombination(
151+
parent: SqlNewGroupBlock,
152+
prevWord: SqlBlock?,
153+
): Boolean =
154+
SqlKeywordUtil.isSetLineKeyword(getNodeText(), parent.getNodeText()) ||
155+
SqlKeywordUtil.isSetLineKeyword(getNodeText(), prevWord?.getNodeText() ?: "")
156+
157+
private fun isFollowedByConditionLoop(): Boolean = childBlocks.lastOrNull() is SqlElConditionLoopCommentBlock
158+
159+
private fun isPrecededByConditionLoop(parent: SqlNewGroupBlock): Boolean {
160+
val lastPrevBlock = prevBlocks.lastOrNull()
161+
return lastPrevBlock is SqlElConditionLoopCommentBlock &&
162+
lastPrevBlock.node.psi.startOffset > parent.node.psi.startOffset
153163
}
154164

155165
/**
@@ -193,11 +203,15 @@ open class SqlBlock(
193203
*/
194204
override fun getChildIndent(): Indent? =
195205
if (isEnableFormat()) {
196-
Indent.getSpaceIndent(4)
206+
Indent.getSpaceIndent(DEFAULT_INDENT_SIZE)
197207
} else {
198208
Indent.getSpaceIndent(0)
199209
}
200210

211+
companion object {
212+
private const val DEFAULT_INDENT_SIZE = 4
213+
}
214+
201215
/**
202216
* Determines whether the block is a leaf node.
203217
*/

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,11 @@ class SqlElConditionLoopCommentBlock(
270270

271271
override fun createGroupIndentLen(): Int = indent.indentLen
272272

273+
/**
274+
* Count the number of [SqlElConditionLoopCommentBlock] within the same parent block.
275+
* Since the current directive is included in the count, **subtract 1 at the end** to exclude itself.
276+
*
277+
*/
273278
private fun getOpenDirectiveCount(parent: SqlBlock): Int {
274279
val conditionLoopDirectives: List<SqlElConditionLoopCommentBlock> =
275280
parent

src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlPostProcessor.kt

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ import com.intellij.psi.impl.source.codeStyle.PostFormatProcessor
2727
import org.domaframework.doma.intellij.setting.SqlLanguage
2828

2929
class SqlPostProcessor : PostFormatProcessor {
30+
companion object {
31+
private const val FILE_END_PADDING = " \n"
32+
}
33+
34+
private val trailingSpacesRegex = Regex(" +(\r?\n)")
35+
3036
override fun processElement(
3137
source: PsiElement,
3238
settings: CodeStyleSettings,
@@ -37,25 +43,44 @@ class SqlPostProcessor : PostFormatProcessor {
3743
rangeToReformat: TextRange,
3844
settings: CodeStyleSettings,
3945
): TextRange {
40-
if (source.language != SqlLanguage.INSTANCE) return rangeToReformat
41-
42-
val project: Project = source.project
43-
val document = PsiDocumentManager.getInstance(project).getDocument(source) ?: return rangeToReformat
46+
if (!isSqlFile(source)) {
47+
return rangeToReformat
48+
}
4449

45-
val originalText = document.text
46-
val withoutTrailingSpaces = originalText.replace(Regex(" +(\r?\n)"), "$1")
47-
val finalText = withoutTrailingSpaces.trimEnd() + " \n"
50+
val document = getDocument(source) ?: return rangeToReformat
51+
val processedText = processDocumentText(document.text)
4852

49-
if (originalText == finalText) {
53+
if (document.text == processedText) {
5054
return rangeToReformat
5155
}
5256

57+
updateDocument(source.project, document, processedText)
58+
return TextRange(0, processedText.length)
59+
}
60+
61+
private fun isSqlFile(source: PsiFile): Boolean = source.language == SqlLanguage.INSTANCE
62+
63+
private fun getDocument(source: PsiFile) = PsiDocumentManager.getInstance(source.project).getDocument(source)
64+
65+
private fun processDocumentText(originalText: String): String {
66+
val withoutTrailingSpaces = removeTrailingSpaces(originalText)
67+
return ensureProperFileEnding(withoutTrailingSpaces)
68+
}
69+
70+
private fun removeTrailingSpaces(text: String): String = text.replace(trailingSpacesRegex, "$1")
71+
72+
private fun ensureProperFileEnding(text: String): String = text.trimEnd() + FILE_END_PADDING
73+
74+
private fun updateDocument(
75+
project: Project,
76+
document: com.intellij.openapi.editor.Document,
77+
newText: String,
78+
) {
5379
ApplicationManager.getApplication().invokeAndWait {
5480
WriteCommandAction.runWriteCommandAction(project) {
55-
document.setText(finalText)
81+
document.setText(newText)
5682
PsiDocumentManager.getInstance(project).commitDocument(document)
5783
}
5884
}
59-
return TextRange(0, finalText.length)
6085
}
6186
}

0 commit comments

Comments
 (0)