Skip to content

Commit 7728471

Browse files
authored
Merge pull request #229 from domaframework/fix/dao-parameter-suggestions
Fix FieldAccess code completion
2 parents 9b321c1 + 85d50aa commit 7728471

15 files changed

+368
-153
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
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.contributor.sql.processor
17+
18+
import com.intellij.psi.PsiElement
19+
import com.intellij.psi.PsiErrorElement
20+
import com.intellij.psi.PsiWhiteSpace
21+
import com.intellij.psi.util.PsiTreeUtil
22+
import com.intellij.psi.util.elementType
23+
import com.intellij.psi.util.prevLeafs
24+
import org.domaframework.doma.intellij.extension.psi.isNotWhiteSpace
25+
import org.domaframework.doma.intellij.psi.SqlBlockComment
26+
import org.domaframework.doma.intellij.psi.SqlElIdExpr
27+
import org.domaframework.doma.intellij.psi.SqlElParameters
28+
import org.domaframework.doma.intellij.psi.SqlElTermExpr
29+
import org.domaframework.doma.intellij.psi.SqlTypes
30+
31+
abstract class SqlCompletionBlockProcessor {
32+
abstract fun generateBlock(targetElement: PsiElement): List<PsiElement>?
33+
34+
protected fun filterBlocks(blocks: List<PsiElement>): List<PsiElement> =
35+
blocks
36+
.filter {
37+
it is SqlElIdExpr || it.elementType == SqlTypes.EL_IDENTIFIER || it == blocks.last()
38+
}.sortedBy { it.textOffset }
39+
40+
// Get the list of elements before itself
41+
protected fun findSelfBlocks(targetElement: PsiElement): List<PsiElement> {
42+
val prevElements =
43+
targetElement.prevLeafs
44+
.takeWhile {
45+
it.elementType != SqlTypes.BLOCK_COMMENT_START &&
46+
!isSqlElSymbol(it) &&
47+
it.elementType != SqlTypes.AT_SIGN &&
48+
it !is SqlElTermExpr &&
49+
it !is SqlBlockComment
50+
}.toList()
51+
52+
var inParameter = false
53+
val formatElements = mutableListOf<PsiElement>()
54+
prevElements.forEach { prev ->
55+
if (prev.elementType == SqlTypes.RIGHT_PAREN) inParameter = true
56+
if (!inParameter) {
57+
formatElements.add(prev)
58+
}
59+
if (prev.elementType == SqlTypes.LEFT_PAREN) inParameter = false
60+
}
61+
62+
val filterElements =
63+
formatElements
64+
.takeWhile { it !is PsiWhiteSpace }
65+
.filter {
66+
it is PsiErrorElement ||
67+
it is SqlElIdExpr ||
68+
it.elementType == SqlTypes.EL_IDENTIFIER
69+
}.filter {
70+
it.isNotWhiteSpace() &&
71+
PsiTreeUtil.getParentOfType(it, SqlElParameters::class.java) == null
72+
}.plus(targetElement)
73+
.sortedBy { it.textOffset }
74+
75+
return if (filterElements.isNotEmpty()) filterElements else emptyList()
76+
}
77+
78+
private fun isSqlElSymbol(element: PsiElement): Boolean =
79+
element.elementType == SqlTypes.EL_PLUS ||
80+
element.elementType == SqlTypes.EL_MINUS ||
81+
element.elementType == SqlTypes.ASTERISK ||
82+
element.elementType == SqlTypes.EL_DIVIDE_EXPR ||
83+
element.elementType == SqlTypes.EL_EQ ||
84+
element.elementType == SqlTypes.EL_NE ||
85+
element.elementType == SqlTypes.EL_LE_EXPR ||
86+
element.elementType == SqlTypes.EL_LT_EXPR ||
87+
element.elementType == SqlTypes.EL_GE_EXPR ||
88+
element.elementType == SqlTypes.EL_GT_EXPR ||
89+
element.elementType == SqlTypes.EL_AND ||
90+
element.elementType == SqlTypes.EL_NOT ||
91+
element.elementType == SqlTypes.SEPARATOR
92+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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.contributor.sql.processor
17+
18+
import com.intellij.psi.PsiElement
19+
20+
class SqlCompletionDirectiveBlockProcessor : SqlCompletionBlockProcessor() {
21+
override fun generateBlock(targetElement: PsiElement): List<PsiElement>? {
22+
val prevElms = findSelfBlocks(targetElement)
23+
if (prevElms.isNotEmpty()) {
24+
return filterBlocks(prevElms)
25+
}
26+
return null
27+
}
28+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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.contributor.sql.processor
17+
18+
import com.intellij.psi.PsiElement
19+
import com.intellij.psi.PsiWhiteSpace
20+
import com.intellij.psi.util.PsiTreeUtil
21+
import com.intellij.psi.util.elementType
22+
import org.domaframework.doma.intellij.psi.SqlTypes
23+
24+
class SqlCompletionOtherBlockProcessor : SqlCompletionBlockProcessor() {
25+
/**
26+
* Generate a list of related elements for suggesting regular DAO argument parameters
27+
* and instance properties of field access elements.
28+
*
29+
* @param targetElement Element at the caret position.
30+
* @return List of preceding elements related to the caret position.
31+
*/
32+
override fun generateBlock(targetElement: PsiElement): List<PsiElement> {
33+
// When entering a new bind variable, an empty list is returned and element names defined as DAO argument parameters
34+
// or in loop directives are suggested.
35+
if (targetElement is PsiWhiteSpace &&
36+
targetElement.text.length > 1 &&
37+
PsiTreeUtil.prevLeaf(targetElement, true)?.elementType != SqlTypes.DOT
38+
) {
39+
return emptyList()
40+
}
41+
42+
// For SqlElFieldAccessExpr,this is the list from the top element to the element at the caret position.
43+
val prevElms = findSelfBlocks(targetElement)
44+
if (prevElms.isNotEmpty()) {
45+
return filterBlocks(prevElms)
46+
}
47+
return emptyList()
48+
}
49+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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.contributor.sql.processor
17+
18+
import com.intellij.psi.PsiElement
19+
import com.intellij.psi.util.PsiTreeUtil
20+
import com.intellij.psi.util.elementType
21+
import com.intellij.psi.util.prevLeafs
22+
import org.domaframework.doma.intellij.extension.psi.isNotWhiteSpace
23+
import org.domaframework.doma.intellij.psi.SqlElFieldAccessExpr
24+
import org.domaframework.doma.intellij.psi.SqlElParameters
25+
import org.domaframework.doma.intellij.psi.SqlTypes
26+
import kotlin.collections.addAll
27+
28+
class SqlCompletionParameterArgsBlockProcessor(
29+
private val targetElement: PsiElement,
30+
) : SqlCompletionBlockProcessor() {
31+
override fun generateBlock(targetElement: PsiElement): List<PsiElement> = emptyList()
32+
33+
/**
34+
* Generates the first argument block for a given parameter parent element.
35+
* This method collects all children of the parameter parent, including nested field access expressions.
36+
*
37+
* @param parameterParent The parent PsiElement of the parameter.
38+
* @return A list of PsiElements representing the first argument block.
39+
*/
40+
fun generateFirstArgsBlock(parameterParent: PsiElement): List<PsiElement> {
41+
val children = mutableListOf<PsiElement>()
42+
parameterParent.children.forEach { child ->
43+
if (child is SqlElFieldAccessExpr) {
44+
children.addAll(child.children)
45+
} else {
46+
children.add(child)
47+
}
48+
}
49+
return children
50+
}
51+
52+
/**
53+
* Retrieves the parent element of the second argument block.
54+
* This method traverses previous leaf elements to find the parent of type SqlElParameters.
55+
*
56+
* @return The parent PsiElement of the second argument block, or null if not found.
57+
*/
58+
fun getSecondArgsParent(): PsiElement? =
59+
targetElement.prevLeafs
60+
.takeWhile {
61+
it.isNotWhiteSpace() &&
62+
it.elementType != SqlTypes.LEFT_PAREN
63+
}.firstOrNull {
64+
PsiTreeUtil.getParentOfType(
65+
it,
66+
SqlElParameters::class.java,
67+
) != null
68+
}
69+
70+
fun generateSecondArgsBlock(parameterArg: PsiElement): List<PsiElement> {
71+
val parameterParent = PsiTreeUtil.getParentOfType(parameterArg, SqlElParameters::class.java)
72+
val children = mutableListOf<PsiElement>()
73+
parameterParent
74+
?.children
75+
?.reversed()
76+
?.takeWhile {
77+
it.nextSibling?.elementType != SqlTypes.COMMA
78+
}?.forEach { child ->
79+
if (child is SqlElFieldAccessExpr) {
80+
children.addAll(child.children)
81+
} else {
82+
children.add(child)
83+
}
84+
}
85+
val blocks = children.reversed()
86+
87+
return filterBlocks(blocks)
88+
}
89+
}

0 commit comments

Comments
 (0)