Skip to content

Commit 66bed16

Browse files
authored
Merge pull request #331 from domaframework/feature/sql-format-support-injectopn-sql
Apply Formatting to Injected SQL
2 parents d81b9f5 + db2e802 commit 66bed16

File tree

16 files changed

+487
-99
lines changed

16 files changed

+487
-99
lines changed

src/main/kotlin/org/domaframework/doma/intellij/common/psi/PsiDaoMethod.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
package org.domaframework.doma.intellij.common.psi
1717

1818
import com.intellij.lang.Language
19-
import com.intellij.lang.injection.InjectedLanguageManager
2019
import com.intellij.openapi.application.ApplicationManager
2120
import com.intellij.openapi.command.WriteCommandAction
2221
import com.intellij.openapi.fileEditor.FileEditorManager
@@ -150,7 +149,6 @@ class PsiDaoMethod(
150149
}
151150
// the injection part as a custom language file
152151
getSqlAnnotation()?.let { annotation ->
153-
InjectedLanguageManager.getInstance(psiProject)
154152
annotation.parameterList.children
155153
.firstOrNull { it is PsiNameValuePair }
156154
?.let { sql ->
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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.common.util
17+
18+
import com.intellij.lang.injection.InjectedLanguageManager
19+
import com.intellij.openapi.project.Project
20+
import com.intellij.psi.PsiFile
21+
import com.intellij.psi.PsiLiteralExpression
22+
import org.domaframework.doma.intellij.common.isJavaOrKotlinFileType
23+
24+
object InjectionSqlUtil {
25+
fun initInjectionElement(
26+
basePsiFile: PsiFile,
27+
project: Project,
28+
literal: PsiLiteralExpression,
29+
): PsiFile? =
30+
if (isJavaOrKotlinFileType(basePsiFile)) {
31+
val injectedLanguageManager = InjectedLanguageManager.getInstance(project)
32+
injectedLanguageManager
33+
.getInjectedPsiFiles(literal)
34+
?.firstOrNull()
35+
?.first as? PsiFile
36+
} else {
37+
null
38+
}
39+
40+
fun isInjectedSqlFile(source: PsiFile): Boolean {
41+
val injectedLanguageManager = InjectedLanguageManager.getInstance(source.project)
42+
return injectedLanguageManager.isInjectedFragment(source)
43+
}
44+
}

src/main/kotlin/org/domaframework/doma/intellij/common/util/StringUtil.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package org.domaframework.doma.intellij.common.util
1717

1818
object StringUtil {
19+
const val LINE_SEPARATE: String = "\n"
20+
1921
fun getSqlElClassText(text: String): String =
2022
text
2123
.substringAfter("@")

src/main/kotlin/org/domaframework/doma/intellij/document/ForItemElementDocumentationProvider.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package org.domaframework.doma.intellij.document
1818
import com.intellij.lang.documentation.AbstractDocumentationProvider
1919
import com.intellij.psi.PsiElement
2020
import com.intellij.psi.util.PsiTreeUtil
21+
import org.domaframework.doma.intellij.common.util.StringUtil
2122
import org.domaframework.doma.intellij.document.generator.DocumentDaoParameterGenerator
2223
import org.domaframework.doma.intellij.document.generator.DocumentStaticFieldGenerator
2324
import org.domaframework.doma.intellij.psi.SqlElIdExpr
@@ -62,7 +63,7 @@ class ForItemElementDocumentationProvider : AbstractDocumentationProvider() {
6263

6364
generator.generateDocument()
6465

65-
return result.joinToString("\n")
66+
return result.joinToString(StringUtil.LINE_SEPARATE)
6667
}
6768

6869
override fun generateHoverDoc(
@@ -77,6 +78,6 @@ class ForItemElementDocumentationProvider : AbstractDocumentationProvider() {
7778
val result: MutableList<String?> = LinkedList<String?>()
7879
val typeDocument = generateDoc(element, originalElement)
7980
result.add(typeDocument)
80-
return result.joinToString("\n")
81+
return result.joinToString(StringUtil.LINE_SEPARATE)
8182
}
8283
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package org.domaframework.doma.intellij.formatter.block.comment
1717

1818
import com.intellij.lang.ASTNode
1919
import com.intellij.psi.util.PsiTreeUtil
20+
import org.domaframework.doma.intellij.common.util.StringUtil
2021
import org.domaframework.doma.intellij.formatter.block.SqlBlock
2122
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext
2223

@@ -27,5 +28,6 @@ open class SqlBlockCommentBlock(
2728
node,
2829
context,
2930
) {
30-
override fun isSaveSpace(lastGroup: SqlBlock?): Boolean = PsiTreeUtil.prevLeaf(node.psi)?.text?.contains("\n") == true
31+
override fun isSaveSpace(lastGroup: SqlBlock?): Boolean =
32+
PsiTreeUtil.prevLeaf(node.psi)?.text?.contains(StringUtil.LINE_SEPARATE) == true
3133
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package org.domaframework.doma.intellij.formatter.block.comment
1818
import com.intellij.lang.ASTNode
1919
import com.intellij.psi.formatter.common.AbstractBlock
2020
import com.intellij.psi.util.PsiTreeUtil
21+
import org.domaframework.doma.intellij.common.util.StringUtil
2122
import org.domaframework.doma.intellij.formatter.block.SqlBlock
2223
import org.domaframework.doma.intellij.formatter.util.IndentType
2324
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext
@@ -60,5 +61,5 @@ abstract class SqlDefaultCommentBlock(
6061
}
6162
}
6263

63-
override fun isSaveSpace(lastGroup: SqlBlock?) = PsiTreeUtil.prevLeaf(node.psi)?.text?.contains("\n") == true
64+
override fun isSaveSpace(lastGroup: SqlBlock?) = PsiTreeUtil.prevLeaf(node.psi)?.text?.contains(StringUtil.LINE_SEPARATE) == true
6465
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import com.intellij.psi.PsiWhiteSpace
2222
import com.intellij.psi.formatter.common.AbstractBlock
2323
import com.intellij.psi.util.PsiTreeUtil
2424
import com.intellij.psi.util.elementType
25+
import org.domaframework.doma.intellij.common.util.StringUtil
2526
import org.domaframework.doma.intellij.common.util.TypeUtil
2627
import org.domaframework.doma.intellij.extension.expr.isConditionOrLoopDirective
2728
import org.domaframework.doma.intellij.formatter.block.SqlBlock
@@ -108,7 +109,7 @@ class SqlElConditionLoopCommentBlock(
108109
// If the child is a condition loop directive, align its indentation with the parent directive
109110
child.indent.indentLen = indent.indentLen.plus(2)
110111
} else if (child is SqlLineCommentBlock) {
111-
if (PsiTreeUtil.prevLeaf(child.node.psi, false)?.text?.contains("\n") == true) {
112+
if (PsiTreeUtil.prevLeaf(child.node.psi, false)?.text?.contains(StringUtil.LINE_SEPARATE) == true) {
112113
child.indent.indentLen = indent.groupIndentLen
113114
} else {
114115
child.indent.indentLen = 1

src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlCustomSpacingBuilder.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import com.intellij.formatting.ASTBlock
1919
import com.intellij.formatting.Block
2020
import com.intellij.formatting.Spacing
2121
import com.intellij.psi.tree.IElementType
22+
import org.domaframework.doma.intellij.common.util.StringUtil
2223
import org.domaframework.doma.intellij.formatter.block.SqlBlock
2324
import org.domaframework.doma.intellij.formatter.block.SqlRightPatternBlock
2425
import org.domaframework.doma.intellij.formatter.block.SqlWhitespaceBlock
@@ -79,8 +80,8 @@ class SqlCustomSpacingBuilder {
7980
null -> return nonSpacing
8081
is SqlWhitespaceBlock -> {
8182
val indentLen: Int = child2.indent.indentLen
82-
val afterNewLine = child1.getNodeText().substringAfterLast("\n", "")
83-
if (child1.getNodeText().contains("\n")) {
83+
val afterNewLine = child1.getNodeText().substringAfterLast(StringUtil.LINE_SEPARATE, "")
84+
if (child1.getNodeText().contains(StringUtil.LINE_SEPARATE)) {
8485
val currentIndent = afterNewLine.length
8586
val newIndent =
8687
if (currentIndent != indentLen) {

src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlFormattingModelBuilder.kt

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,25 +38,35 @@ import org.domaframework.doma.intellij.setting.state.DomaToolsFormatEnableSettin
3838
class SqlFormattingModelBuilder : FormattingModelBuilder {
3939
override fun createModel(formattingContext: FormattingContext): FormattingModel {
4040
val codeStyleSettings = formattingContext.codeStyleSettings
41+
42+
return createRegularSQLModel(formattingContext, codeStyleSettings)
43+
}
44+
45+
private fun createRegularSQLModel(
46+
formattingContext: FormattingContext,
47+
settings: CodeStyleSettings,
48+
): FormattingModel {
4149
val setting = DomaToolsFormatEnableSettings.getInstance()
4250
val isEnableFormat = setting.state.isEnableSqlFormat == true
4351
val formatMode = formattingContext.formattingMode
44-
val spacingBuilder = createSpaceBuilder(codeStyleSettings)
52+
val spacingBuilder = createSpaceBuilder(settings)
4553
val customSpacingBuilder = createCustomSpacingBuilder()
4654

55+
val block =
56+
SqlFileBlock(
57+
formattingContext.node,
58+
Wrap.createWrap(WrapType.NONE, false),
59+
Alignment.createAlignment(),
60+
customSpacingBuilder,
61+
spacingBuilder,
62+
isEnableFormat,
63+
formatMode,
64+
)
4765
return FormattingModelProvider
4866
.createFormattingModelForPsiFile(
4967
formattingContext.containingFile,
50-
SqlFileBlock(
51-
formattingContext.node,
52-
Wrap.createWrap(WrapType.NONE, false),
53-
Alignment.createAlignment(),
54-
customSpacingBuilder,
55-
spacingBuilder,
56-
isEnableFormat,
57-
formatMode,
58-
),
59-
codeStyleSettings,
68+
block,
69+
settings,
6070
)
6171
}
6272

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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.processor
17+
18+
import com.intellij.lang.injection.InjectedLanguageManager
19+
import com.intellij.openapi.application.ApplicationManager
20+
import com.intellij.openapi.command.WriteCommandAction
21+
import com.intellij.openapi.editor.Document
22+
import com.intellij.openapi.project.Project
23+
import com.intellij.openapi.util.TextRange
24+
import com.intellij.psi.PsiDocumentManager
25+
import com.intellij.psi.PsiElement
26+
import com.intellij.psi.PsiFile
27+
import com.intellij.psi.codeStyle.CodeStyleSettings
28+
import org.domaframework.doma.intellij.setting.SqlLanguage
29+
30+
class SqlFormatPostProcessor : SqlPostProcessor() {
31+
override fun processElement(
32+
source: PsiElement,
33+
settings: CodeStyleSettings,
34+
): PsiElement = source
35+
36+
override fun processText(
37+
source: PsiFile,
38+
rangeToReformat: TextRange,
39+
settings: CodeStyleSettings,
40+
): TextRange {
41+
if (!isSqlFile(source) || isInjectedSqlFile(source)) {
42+
return rangeToReformat
43+
}
44+
45+
val document = getDocument(source) ?: return rangeToReformat
46+
val processedText = processDocumentText(document.text, true)
47+
48+
if (document.text == processedText) {
49+
return rangeToReformat
50+
}
51+
52+
updateDocument(source.project, document, processedText)
53+
return TextRange(0, processedText.length)
54+
}
55+
56+
private fun isSqlFile(source: PsiFile): Boolean = source.language == SqlLanguage.INSTANCE
57+
58+
private fun isInjectedSqlFile(source: PsiFile): Boolean {
59+
val injectedLanguageManager = InjectedLanguageManager.getInstance(source.project)
60+
return injectedLanguageManager.isInjectedFragment(source)
61+
}
62+
63+
private fun getDocument(source: PsiFile) = PsiDocumentManager.getInstance(source.project).getDocument(source)
64+
65+
private fun updateDocument(
66+
project: Project,
67+
document: Document,
68+
newText: String,
69+
) {
70+
ApplicationManager.getApplication().invokeAndWait {
71+
WriteCommandAction.runWriteCommandAction(project) {
72+
document.setText(newText)
73+
PsiDocumentManager.getInstance(project).commitDocument(document)
74+
}
75+
}
76+
}
77+
}

0 commit comments

Comments
 (0)