Skip to content

Commit 9c9e3e9

Browse files
committed
Update the logic for formatting injected SQL so that it aligns at the specified indentation level, offset downward by the configured indent amount.
1 parent 99f3e1f commit 9c9e3e9

File tree

4 files changed

+47
-52
lines changed

4 files changed

+47
-52
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class SqlFormatPostProcessor : SqlPostProcessor() {
4343
}
4444

4545
val document = getDocument(source) ?: return rangeToReformat
46-
val processedText = processDocumentText(document.text, true)
46+
val processedText = processDocumentText(document.text)
4747

4848
if (document.text == processedText) {
4949
return rangeToReformat

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class SqlInjectionPostProcessor : SqlPostProcessor() {
4646
val visitor = DaoInjectionSqlVisitor(element, project)
4747
element.accept(visitor)
4848
visitor.processAll { text, skipFinalLineBreak ->
49-
processDocumentText(text, skipFinalLineBreak)
49+
processDocumentText(text)
5050
}
5151
}
5252
}

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

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,12 @@ abstract class SqlPostProcessor : PostFormatProcessor {
3636
settings: CodeStyleSettings,
3737
): TextRange = rangeToReformat
3838

39-
protected fun processDocumentText(
40-
originalText: String,
41-
existsOriginalDocument: Boolean,
42-
): String {
39+
protected fun processDocumentText(originalText: String): String {
4340
val withoutTrailingSpaces = removeTrailingSpaces(originalText)
44-
return ensureProperFileEnding(withoutTrailingSpaces, existsOriginalDocument)
41+
return ensureProperFileEnding(withoutTrailingSpaces)
4542
}
4643

4744
private fun removeTrailingSpaces(text: String): String = text.replace(trailingSpacesRegex, "$1")
4845

49-
private fun ensureProperFileEnding(
50-
text: String,
51-
isEndSpace: Boolean,
52-
): String =
53-
text.trimEnd() +
54-
if (isEndSpace) StringUtil.LINE_SEPARATE else ""
46+
private fun ensureProperFileEnding(text: String): String = text.trimEnd() + StringUtil.LINE_SEPARATE
5547
}

src/main/kotlin/org/domaframework/doma/intellij/formatter/visitor/DaoInjectionSqlVisitor.kt

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,14 @@ class DaoInjectionSqlVisitor(
4040
private data class FormattingTask(
4141
val expression: PsiLiteralExpression,
4242
val formattedText: String,
43-
val baseIndent: String,
4443
)
4544

4645
companion object {
4746
private const val TEMP_FILE_PREFIX = "temp_format"
4847
private const val SQL_FILE_EXTENSION = ".sql"
49-
private const val SQL_COMMENT_PATTERN = "^[ \\t]*/\\*"
5048
private const val TRIPLE_QUOTE = "\"\"\""
5149
private const val WRITE_COMMAND_NAME = "Format Injected SQL"
50+
private const val BASE_INDENT = "\t\t\t" // getBaseIndent(formattedSql)
5251
}
5352

5453
private val formattingTasks = mutableListOf<FormattingTask>()
@@ -58,36 +57,39 @@ class DaoInjectionSqlVisitor(
5857
val injected: PsiFile? = InjectionSqlUtil.initInjectionElement(element, project, expression)
5958
if (injected != null) {
6059
// Format SQL and store the task
61-
val originalSqlText = injected.text
62-
val formattedSql = formatAsTemporarySqlFile(originalSqlText)
63-
// Keep the current top line indent
64-
val baseIndent = getBaseIndent(formattedSql)
6560
val originalText = expression.value?.toString() ?: return
66-
67-
if (formattedSql != originalText) {
68-
formattingTasks.add(FormattingTask(expression, formattedSql, baseIndent))
69-
}
61+
val removeIndent = removeIndentLines(originalText)
62+
formattingTasks.add(FormattingTask(expression, removeIndent))
7063
}
7164
}
7265

73-
/**
74-
* Extracts the base indentation from the first non-blank, non-comment line.
75-
*/
76-
private fun getBaseIndent(string: String): String {
77-
val lines = string.lines()
78-
val commentRegex = Regex(SQL_COMMENT_PATTERN)
79-
80-
// Skip blank lines and comment lines
81-
val firstContentLineIndex =
82-
lines.indexOfFirst { line ->
83-
line.isNotBlank() && !commentRegex.matches(line)
66+
private fun removeIndentLines(sqlText: String): String {
67+
val lines = sqlText.lines()
68+
val commentStartRegex = Regex("^[ \t]*/[*][ \t]*\\*")
69+
val commentEndRegex = Regex("\\*/.*$")
70+
var blockComment = false
71+
val removeIndentLines =
72+
lines.map { line ->
73+
if (blockComment) {
74+
if (commentEndRegex.containsMatchIn(line)) {
75+
blockComment = false
76+
}
77+
SINGLE_SPACE.plus(line.dropWhile { it.isWhitespace() })
78+
} else {
79+
val baseLine =
80+
if (commentStartRegex.containsMatchIn(line)) {
81+
blockComment = true
82+
// Exclude spaces between `/*` and the comment content element,
83+
// as IntelliJ IDEA's Java formatter may insert a space there during formatting.
84+
line.replace(commentStartRegex, "/**")
85+
} else {
86+
line
87+
}
88+
baseLine.dropWhile { it.isWhitespace() }
89+
}
8490
}
8591

86-
return if (firstContentLineIndex >= 0) {
87-
lines[firstContentLineIndex].takeWhile { it.isWhitespace() }
88-
} else {
89-
""
90-
}
92+
return removeIndentLines.joinToString(StringUtil.LINE_SEPARATE)
9193
}
9294

9395
/**
@@ -138,10 +140,11 @@ class DaoInjectionSqlVisitor(
138140
*/
139141
private fun replaceHostStringLiteral(
140142
task: FormattingTask,
141-
removeSpace: (String, Boolean) -> String,
143+
sqlPostProcessorProcess: (String, Boolean) -> String,
142144
) {
143145
try {
144-
val formattedLiteral = createFormattedLiteral(task, removeSpace)
146+
// Keep the current top line indent
147+
val formattedLiteral = createFormattedLiteral(task, sqlPostProcessorProcess)
145148
replaceInDocument(task.expression, formattedLiteral)
146149
} catch (_: Exception) {
147150
// Silently ignore formatting failures
@@ -150,16 +153,19 @@ class DaoInjectionSqlVisitor(
150153

151154
private fun createFormattedLiteral(
152155
task: FormattingTask,
153-
removeSpace: (String, Boolean) -> String,
156+
sqlPostProcessorProcess: (String, Boolean) -> String,
154157
): String {
155-
val newLiteralText = createFormattedLiteralText(task.formattedText)
156-
val normalizedText = normalizeIndentation(newLiteralText, task.baseIndent)
157-
val cleanedText = removeSpace(normalizedText, false)
158+
// Retrieve the same formatted string as when formatting a regular SQL file.
159+
val formattedSql = formatAsTemporarySqlFile(task.formattedText)
160+
val cleanedText = sqlPostProcessorProcess(formattedSql, false)
161+
// Generate text aligned with the literal element using the formatted string.
162+
val newLiteralText = createFormattedLiteralText(cleanedText)
163+
val normalizedText = normalizeIndentation(newLiteralText)
158164

159165
val elementFactory =
160166
com.intellij.psi.JavaPsiFacade
161167
.getElementFactory(project)
162-
val newLiteral = elementFactory.createExpressionFromText(cleanedText, task.expression)
168+
val newLiteral = elementFactory.createExpressionFromText(normalizedText, task.expression)
163169
return newLiteral.text
164170
}
165171

@@ -192,10 +198,7 @@ class DaoInjectionSqlVisitor(
192198
/**
193199
* Normalizes indentation by removing base indent and reapplying it consistently.
194200
*/
195-
private fun normalizeIndentation(
196-
sqlText: String,
197-
baseIndent: String,
198-
): String {
201+
private fun normalizeIndentation(sqlText: String): String {
199202
val lines = sqlText.lines()
200203
if (lines.isEmpty()) return sqlText
201204

@@ -206,8 +209,8 @@ class DaoInjectionSqlVisitor(
206209
contentLines.map { line ->
207210
when {
208211
line.isBlank() -> line
209-
line.startsWith(baseIndent) -> baseIndent + line.removePrefix(baseIndent)
210-
else -> baseIndent + line
212+
line.startsWith(BASE_INDENT) -> BASE_INDENT + line.removePrefix(BASE_INDENT)
213+
else -> BASE_INDENT + line
211214
}
212215
}
213216

0 commit comments

Comments
 (0)