Skip to content

Commit 315fa06

Browse files
authored
Merge pull request #348 from domaframework/fix/sql-format-reformat-code
Support code reformatting on injected SQL
2 parents e2405b1 + ec649b1 commit 315fa06

File tree

2 files changed

+51
-17
lines changed

2 files changed

+51
-17
lines changed

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

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@
1515
*/
1616
package org.domaframework.doma.intellij.formatter.processor
1717

18-
import com.intellij.openapi.project.Project
18+
import com.intellij.lang.injection.InjectedLanguageManager
1919
import com.intellij.openapi.util.TextRange
2020
import com.intellij.psi.PsiElement
2121
import com.intellij.psi.PsiFile
22+
import com.intellij.psi.PsiLiteralExpression
2223
import com.intellij.psi.codeStyle.CodeStyleSettings
2324
import org.domaframework.doma.intellij.common.dao.getDaoClass
2425
import org.domaframework.doma.intellij.common.isJavaOrKotlinFileType
26+
import org.domaframework.doma.intellij.common.isSupportFileType
2527
import org.domaframework.doma.intellij.formatter.visitor.DaoInjectionSqlVisitor
2628

2729
class SqlInjectionPostProcessor : SqlPostProcessor() {
@@ -35,17 +37,49 @@ class SqlInjectionPostProcessor : SqlPostProcessor() {
3537
rangeToReformat: TextRange,
3638
settings: CodeStyleSettings,
3739
): TextRange {
38-
if (!isJavaOrKotlinFileType(source) || getDaoClass(source) == null) return rangeToReformat
40+
if (!shouldProcessFile(source)) {
41+
return rangeToReformat
42+
}
43+
44+
val manager = InjectedLanguageManager.getInstance(source.project)
45+
if (manager.isInjectedFragment(source)) {
46+
processInjectedFragment(source, manager)
47+
} else {
48+
processRegularFile(source)
49+
}
3950

40-
processInjected(source)
4151
return rangeToReformat
4252
}
4353

44-
private fun processInjected(element: PsiFile) {
45-
val project: Project = element.project
46-
val visitor = DaoInjectionSqlVisitor(element, project)
47-
element.accept(visitor)
48-
visitor.processAll { text, skipFinalLineBreak ->
54+
private fun shouldProcessFile(source: PsiFile): Boolean {
55+
val manager = InjectedLanguageManager.getInstance(source.project)
56+
val isInjectedSql = if (isSupportFileType(source)) manager.isInjectedFragment(source) else false
57+
val isDaoFile = isJavaOrKotlinFileType(source) && getDaoClass(source) != null
58+
59+
return isInjectedSql || isDaoFile
60+
}
61+
62+
private fun processInjectedFragment(
63+
source: PsiFile,
64+
manager: InjectedLanguageManager,
65+
) {
66+
val host = manager.getInjectionHost(source) as? PsiLiteralExpression ?: return
67+
val hostDaoFile = host.containingFile
68+
val originalText = host.value?.toString() ?: return
69+
70+
val visitor = DaoInjectionSqlVisitor(hostDaoFile, source.project)
71+
val formattingTask = DaoInjectionSqlVisitor.FormattingTask(host, originalText)
72+
73+
visitor.replaceHostStringLiteral(formattingTask) { text ->
74+
processDocumentText(text)
75+
}
76+
}
77+
78+
private fun processRegularFile(source: PsiFile) {
79+
val visitor = DaoInjectionSqlVisitor(source, source.project)
80+
source.accept(visitor)
81+
82+
visitor.processAll { text ->
4983
processDocumentText(text)
5084
}
5185
}

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class DaoInjectionSqlVisitor(
3636
private val element: PsiFile,
3737
private val project: Project,
3838
) : JavaRecursiveElementVisitor() {
39-
private data class FormattingTask(
39+
data class FormattingTask(
4040
val expression: PsiLiteralExpression,
4141
val formattedText: String,
4242
)
@@ -58,8 +58,7 @@ class DaoInjectionSqlVisitor(
5858
if (injected != null) {
5959
// Format SQL and store the task
6060
val originalText = expression.value?.toString() ?: return
61-
val removeIndent = removeIndentLines(originalText)
62-
formattingTasks.add(FormattingTask(expression, removeIndent))
61+
formattingTasks.add(FormattingTask(expression, originalText))
6362
}
6463
}
6564

@@ -88,7 +87,7 @@ class DaoInjectionSqlVisitor(
8887
* Processes all collected formatting tasks in a single write action.
8988
* @param removeSpace Function to remove trailing spaces from formatted text
9089
*/
91-
fun processAll(removeSpace: (String, Boolean) -> String) {
90+
fun processAll(removeSpace: (String) -> String) {
9291
if (formattingTasks.isEmpty()) return
9392

9493
// Apply all formatting tasks in a single write action
@@ -130,9 +129,9 @@ class DaoInjectionSqlVisitor(
130129
/**
131130
* Replaces the host Java string literal with formatted SQL text.
132131
*/
133-
private fun replaceHostStringLiteral(
132+
fun replaceHostStringLiteral(
134133
task: FormattingTask,
135-
sqlPostProcessorProcess: (String, Boolean) -> String,
134+
sqlPostProcessorProcess: (String) -> String,
136135
) {
137136
try {
138137
// Keep the current top line indent
@@ -145,11 +144,12 @@ class DaoInjectionSqlVisitor(
145144

146145
private fun createFormattedLiteral(
147146
task: FormattingTask,
148-
sqlPostProcessorProcess: (String, Boolean) -> String,
147+
sqlPostProcessorProcess: (String) -> String,
149148
): String {
150149
// Retrieve the same formatted string as when formatting a regular SQL file.
151-
val formattedSql = formatAsTemporarySqlFile(task.formattedText)
152-
val cleanedText = sqlPostProcessorProcess(formattedSql, false)
150+
val removeIndent = removeIndentLines(task.formattedText)
151+
val formattedSql = formatAsTemporarySqlFile(removeIndent)
152+
val cleanedText = sqlPostProcessorProcess(formattedSql)
153153
// Generate text aligned with the literal element using the formatted string.
154154
val newLiteralText = createFormattedLiteralText(cleanedText)
155155
val normalizedText = normalizeIndentation(newLiteralText)

0 commit comments

Comments
 (0)