Skip to content

Commit ca616fa

Browse files
committed
Fix indentation for escaped column names that match function or keyword names.
1 parent e763d69 commit ca616fa

File tree

7 files changed

+225
-181
lines changed

7 files changed

+225
-181
lines changed

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

Lines changed: 119 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -147,154 +147,130 @@ open class SqlFileBlock(
147147
child: ASTNode,
148148
prevBlock: SqlBlock?,
149149
): SqlBlock {
150-
val defaultFormatCtx =
151-
SqlBlockFormattingContext(
152-
wrap,
153-
alignment,
154-
spacingBuilder,
155-
isEnableFormat(),
156-
formatMode,
157-
)
150+
val defaultFormatCtx = createDefaultFormattingContext()
158151
val lastGroup = blockBuilder.getLastGroupTopNodeIndexHistory()
159-
160152
val lastGroupFilteredDirective = blockBuilder.getLastGroupFilterDirective()
161-
return when (child.elementType) {
162-
SqlTypes.KEYWORD -> {
163-
if (blockUtil.hasEscapeBeforeWhiteSpace(blocks.lastOrNull() as? SqlBlock?, child)) {
164-
return SqlWordBlock(
165-
child,
166-
defaultFormatCtx,
167-
)
168-
}
169-
return blockUtil.getKeywordBlock(
170-
child,
171-
blockBuilder.getLastGroupTopNodeIndexHistory(),
172-
)
173-
}
174153

175-
SqlTypes.DATATYPE -> {
176-
SqlDataTypeBlock(
177-
child,
178-
defaultFormatCtx,
179-
)
180-
}
181-
182-
SqlTypes.LEFT_PAREN -> {
183-
return blockUtil.getSubGroupBlock(lastGroup, child, blockBuilder.getGroupTopNodeIndexHistory())
184-
}
185-
186-
SqlTypes.OTHER -> {
187-
return if (lastGroup is SqlUpdateSetGroupBlock &&
188-
lastGroup.columnDefinitionGroupBlock != null
189-
) {
190-
SqlUpdateColumnAssignmentSymbolBlock(
191-
child,
192-
defaultFormatCtx,
193-
)
194-
} else {
195-
val escapeStrings = listOf("\"", "`", "[", "]")
196-
if (escapeStrings.contains(child.text)) {
197-
if (child.text == "[" && prevBlock is SqlArrayWordBlock) {
198-
SqlArrayListGroupBlock(
199-
child,
200-
defaultFormatCtx,
201-
)
202-
} else {
203-
SqlEscapeBlock(
204-
child,
205-
defaultFormatCtx,
206-
)
207-
}
208-
} else {
209-
SqlOtherBlock(
210-
child,
211-
defaultFormatCtx,
212-
)
213-
}
214-
}
215-
}
216-
217-
SqlTypes.RIGHT_PAREN -> return SqlRightPatternBlock(
218-
child,
219-
defaultFormatCtx,
220-
)
154+
return when (child.elementType) {
155+
SqlTypes.KEYWORD -> createKeywordBlock(child, lastGroup)
156+
SqlTypes.DATATYPE -> SqlDataTypeBlock(child, defaultFormatCtx)
157+
SqlTypes.LEFT_PAREN -> blockUtil.getSubGroupBlock(lastGroup, child, blockBuilder.getGroupTopNodeIndexHistory())
158+
SqlTypes.OTHER -> createOtherBlock(child, prevBlock, lastGroup, defaultFormatCtx)
159+
SqlTypes.RIGHT_PAREN -> SqlRightPatternBlock(child, defaultFormatCtx)
160+
SqlTypes.COMMA -> createCommaBlock(child, lastGroup, defaultFormatCtx)
161+
SqlTypes.FUNCTION_NAME -> createFunctionNameBlock(child, lastGroup, defaultFormatCtx)
162+
SqlTypes.WORD -> createWordBlock(child, lastGroup, defaultFormatCtx)
163+
SqlTypes.BLOCK_COMMENT -> createBlockCommentBlock(child, lastGroup, lastGroupFilteredDirective, defaultFormatCtx)
164+
SqlTypes.LINE_COMMENT -> SqlLineCommentBlock(child, defaultFormatCtx)
165+
SqlTypes.PLUS, SqlTypes.MINUS, SqlTypes.ASTERISK, SqlTypes.SLASH -> SqlElSymbolBlock(child, defaultFormatCtx)
166+
SqlTypes.LE, SqlTypes.LT, SqlTypes.EL_EQ, SqlTypes.EL_NE, SqlTypes.GE, SqlTypes.GT -> SqlElSymbolBlock(child, defaultFormatCtx)
167+
SqlTypes.STRING, SqlTypes.NUMBER, SqlTypes.BOOLEAN -> SqlLiteralBlock(child, defaultFormatCtx)
168+
else -> SqlUnknownBlock(child, defaultFormatCtx)
169+
}
170+
}
221171

222-
SqlTypes.COMMA -> {
223-
return if (lastGroup is SqlWithQueryGroupBlock) {
224-
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
225-
} else {
226-
blockUtil.getCommaGroupBlock(lastGroup, child)
227-
}
228-
}
172+
private fun createDefaultFormattingContext(): SqlBlockFormattingContext =
173+
SqlBlockFormattingContext(
174+
wrap,
175+
alignment,
176+
spacingBuilder,
177+
isEnableFormat(),
178+
formatMode,
179+
)
229180

230-
SqlTypes.FUNCTION_NAME -> {
231-
val block = blockUtil.getFunctionName(child, defaultFormatCtx)
232-
if (block != null) {
233-
return block
234-
}
235-
// If it is not followed by a left parenthesis, treat it as a word block
236-
return if (lastGroup is SqlWithQueryGroupBlock) {
237-
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
238-
} else {
239-
blockUtil.getWordBlock(lastGroup, child)
240-
}
241-
}
181+
private fun createKeywordBlock(
182+
child: ASTNode,
183+
lastGroup: SqlBlock?,
184+
): SqlBlock {
185+
if (blockUtil.hasEscapeBeforeWhiteSpace(blocks.lastOrNull() as? SqlBlock?, child)) {
186+
return blockUtil.getWordBlock(lastGroup, child)
187+
}
188+
return blockUtil.getKeywordBlock(
189+
child,
190+
blockBuilder.getLastGroupTopNodeIndexHistory(),
191+
)
192+
}
242193

243-
SqlTypes.WORD -> {
244-
return if (lastGroup is SqlWithQueryGroupBlock) {
245-
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
246-
} else {
247-
blockUtil.getWordBlock(lastGroup, child)
248-
}
249-
}
194+
private fun createOtherBlock(
195+
child: ASTNode,
196+
prevBlock: SqlBlock?,
197+
lastGroup: SqlBlock?,
198+
defaultFormatCtx: SqlBlockFormattingContext,
199+
): SqlBlock {
200+
if (lastGroup is SqlUpdateSetGroupBlock && lastGroup.columnDefinitionGroupBlock != null) {
201+
return SqlUpdateColumnAssignmentSymbolBlock(child, defaultFormatCtx)
202+
}
250203

251-
SqlTypes.BLOCK_COMMENT -> {
252-
val tempBlock =
253-
blockUtil.getBlockCommentBlock(
254-
child,
255-
createBlockDirectiveCommentSpacingBuilder(),
256-
)
257-
if (tempBlock !is SqlElConditionLoopCommentBlock) {
258-
if (lastGroup is SqlWithQueryGroupBlock || lastGroupFilteredDirective is SqlWithQueryGroupBlock) {
259-
return SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
260-
}
261-
}
262-
return if (lastGroup is SqlWithCommonTableGroupBlock) {
263-
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
264-
} else {
265-
tempBlock
266-
}
204+
val escapeStrings = listOf("\"", "`", "[", "]")
205+
if (escapeStrings.contains(child.text)) {
206+
return if (child.text == "[" && prevBlock is SqlArrayWordBlock) {
207+
SqlArrayListGroupBlock(child, defaultFormatCtx)
208+
} else {
209+
SqlEscapeBlock(child, defaultFormatCtx)
267210
}
211+
}
212+
return SqlOtherBlock(child, defaultFormatCtx)
213+
}
268214

269-
SqlTypes.LINE_COMMENT ->
270-
return SqlLineCommentBlock(
271-
child,
272-
defaultFormatCtx,
273-
)
274-
275-
SqlTypes.PLUS, SqlTypes.MINUS, SqlTypes.ASTERISK, SqlTypes.SLASH ->
276-
return SqlElSymbolBlock(
277-
child,
278-
defaultFormatCtx,
279-
)
215+
private fun createCommaBlock(
216+
child: ASTNode,
217+
lastGroup: SqlBlock?,
218+
defaultFormatCtx: SqlBlockFormattingContext,
219+
): SqlBlock =
220+
if (lastGroup is SqlWithQueryGroupBlock) {
221+
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
222+
} else {
223+
blockUtil.getCommaGroupBlock(lastGroup, child)
224+
}
280225

281-
SqlTypes.LE, SqlTypes.LT, SqlTypes.EL_EQ, SqlTypes.EL_NE, SqlTypes.GE, SqlTypes.GT ->
282-
return SqlElSymbolBlock(
283-
child,
284-
defaultFormatCtx,
285-
)
226+
private fun createFunctionNameBlock(
227+
child: ASTNode,
228+
lastGroup: SqlBlock?,
229+
defaultFormatCtx: SqlBlockFormattingContext,
230+
): SqlBlock {
231+
val block = blockUtil.getFunctionName(child, defaultFormatCtx)
232+
if (block != null) {
233+
return block
234+
}
235+
// If it is not followed by a left parenthesis, treat it as a word block
236+
return if (lastGroup is SqlWithQueryGroupBlock) {
237+
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
238+
} else {
239+
blockUtil.getWordBlock(lastGroup, child)
240+
}
241+
}
286242

287-
SqlTypes.STRING, SqlTypes.NUMBER, SqlTypes.BOOLEAN ->
288-
return SqlLiteralBlock(
289-
child,
290-
defaultFormatCtx,
291-
)
243+
private fun createWordBlock(
244+
child: ASTNode,
245+
lastGroup: SqlBlock?,
246+
defaultFormatCtx: SqlBlockFormattingContext,
247+
): SqlBlock =
248+
if (lastGroup is SqlWithQueryGroupBlock) {
249+
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
250+
} else {
251+
blockUtil.getWordBlock(lastGroup, child)
252+
}
292253

293-
else ->
294-
SqlUnknownBlock(
295-
child,
296-
defaultFormatCtx,
297-
)
254+
private fun createBlockCommentBlock(
255+
child: ASTNode,
256+
lastGroup: SqlBlock?,
257+
lastGroupFilteredDirective: SqlBlock?,
258+
defaultFormatCtx: SqlBlockFormattingContext,
259+
): SqlBlock {
260+
val tempBlock =
261+
blockUtil.getBlockCommentBlock(
262+
child,
263+
createBlockDirectiveCommentSpacingBuilder(),
264+
)
265+
if (tempBlock !is SqlElConditionLoopCommentBlock) {
266+
if (lastGroup is SqlWithQueryGroupBlock || lastGroupFilteredDirective is SqlWithQueryGroupBlock) {
267+
return SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
268+
}
269+
}
270+
return if (lastGroup is SqlWithCommonTableGroupBlock) {
271+
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
272+
} else {
273+
tempBlock
298274
}
299275
}
300276

@@ -585,6 +561,13 @@ open class SqlFileBlock(
585561
if (childBlock2.isEndEscape) {
586562
return SqlCustomSpacingBuilder.nonSpacing
587563
}
564+
565+
// When a column definition is enclosed in escape characters,
566+
// calculate the indentation to match the formatting rules of a CREATE query.
567+
CreateClauseHandler
568+
.getColumnDefinitionRawGroupSpacing(childBlock1, childBlock2)
569+
?.let { return it }
570+
588571
return SqlCustomSpacingBuilder().getSpacing(childBlock2)
589572
}
590573

src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/column/SqlColumnDefinitionRawGroupBlock.kt

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package org.domaframework.doma.intellij.formatter.block.group.column
1818
import com.intellij.lang.ASTNode
1919
import com.intellij.psi.formatter.common.AbstractBlock
2020
import org.domaframework.doma.intellij.formatter.block.SqlBlock
21+
import org.domaframework.doma.intellij.formatter.block.other.SqlEscapeBlock
2122
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext
2223
import org.domaframework.doma.intellij.psi.SqlTypes
2324

@@ -32,12 +33,25 @@ open class SqlColumnDefinitionRawGroupBlock(
3233
node,
3334
context,
3435
) {
35-
// TODO Customize indentation within an inline group
36-
open val defaultOffset = 0
37-
val isFirstColumnRaw = node.elementType != SqlTypes.COMMA
36+
companion object {
37+
private const val DEFAULT_OFFSET = 0
38+
private const val ESCAPE_CHARS_LENGTH = 2
39+
private const val FIRST_COLUMN_INDENT = 1
40+
}
3841

42+
val isFirstColumnRaw = node.elementType != SqlTypes.COMMA
3943
open var columnBlock: SqlBlock? = if (isFirstColumnRaw) this else null
4044

45+
fun getColumnNameLength(): Int {
46+
val columnNameLength = columnBlock?.getNodeText()?.length ?: 0
47+
val hasEscapeCharacters = columnBlock?.prevBlocks?.firstOrNull() is SqlEscapeBlock
48+
return if (hasEscapeCharacters) {
49+
columnNameLength + ESCAPE_CHARS_LENGTH
50+
} else {
51+
columnNameLength
52+
}
53+
}
54+
4155
override fun setParentGroupBlock(lastGroup: SqlBlock?) {
4256
super.setParentGroupBlock(lastGroup)
4357
indent.indentLen = createBlockIndentLen()
@@ -47,9 +61,12 @@ open class SqlColumnDefinitionRawGroupBlock(
4761
override fun buildChildren(): MutableList<AbstractBlock> = mutableListOf()
4862

4963
/**
50-
* Right-justify the longest column name in the column definition.
64+
* Calculate indent length for column definition.
65+
* First column has an indent of 1, others use default offset.
5166
*/
52-
override fun createBlockIndentLen(): Int = if (isFirstColumnRaw) 1 else defaultOffset
67+
private fun calculateIndentLength(): Int = if (isFirstColumnRaw) FIRST_COLUMN_INDENT else DEFAULT_OFFSET
68+
69+
override fun createBlockIndentLen(): Int = calculateIndentLength()
5370

5471
override fun isSaveSpace(lastGroup: SqlBlock?): Boolean = true
5572
}

src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/create/SqlCreateTableColumnDefinitionGroupBlock.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,23 @@ class SqlCreateTableColumnDefinitionGroupBlock(
4141
node,
4242
context,
4343
) {
44-
// TODO Customize indentation
45-
override val offset = 2
46-
private val groupOffset = 5
44+
companion object {
45+
private const val COLUMN_INDENT_OFFSET = 2
46+
private const val GROUP_INDENT_OFFSET = 5
47+
}
48+
49+
override val offset = COLUMN_INDENT_OFFSET
4750
val columnRawGroupBlocks = mutableListOf<SqlColumnDefinitionRawGroupBlock>()
4851

4952
fun getMaxColumnNameLength(): Int =
5053
columnRawGroupBlocks.maxOfOrNull { raw ->
51-
raw.columnBlock?.getNodeText()?.length ?: 0
54+
raw.getColumnNameLength()
5255
} ?: 0
5356

5457
override fun setParentGroupBlock(lastGroup: SqlBlock?) {
5558
super.setParentGroupBlock(lastGroup)
5659
indent.indentLen = createBlockIndentLen()
57-
indent.groupIndentLen = indent.indentLen.plus(groupOffset)
60+
indent.groupIndentLen = indent.indentLen.plus(GROUP_INDENT_OFFSET)
5861
}
5962

6063
override fun buildChildren(): MutableList<AbstractBlock> = mutableListOf()

0 commit comments

Comments
 (0)