Skip to content

Commit 51430c8

Browse files
authored
Merge pull request #196 from domaframework/fix/replace-trailing-characters-during-code-completion
Replace Trailing Characters During Code Completion
2 parents 317aee0 + 42c3907 commit 51430c8

File tree

12 files changed

+123
-36
lines changed

12 files changed

+123
-36
lines changed

src/main/kotlin/org/domaframework/doma/intellij/common/sql/directive/DirectiveCompletion.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class DirectiveCompletion(
2323
private val originalFile: PsiFile,
2424
private val bindText: String,
2525
private val element: PsiElement,
26+
private val caretNextText: String,
2627
private val result: CompletionResultSet,
2728
) {
2829
fun directiveHandle(symbol: String): Boolean {
@@ -52,6 +53,7 @@ class DirectiveCompletion(
5253
StaticDirectiveHandler(
5354
originalFile = originalFile,
5455
element = element,
56+
caretNextText = caretNextText,
5557
result = result,
5658
bindText = bindText,
5759
).directiveHandle()

src/main/kotlin/org/domaframework/doma/intellij/common/sql/directive/StaticDirectiveHandler.kt

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import com.intellij.openapi.module.Module
2020
import com.intellij.psi.PsiElement
2121
import com.intellij.psi.util.PsiTreeUtil
2222
import com.intellij.psi.util.elementType
23-
import org.domaframework.doma.intellij.common.sql.directive.collector.StaticBuildFunctionCollector
23+
import org.domaframework.doma.intellij.common.sql.directive.collector.FunctionCallCollector
2424
import org.domaframework.doma.intellij.common.sql.directive.collector.StaticClassPackageCollector
2525
import org.domaframework.doma.intellij.common.sql.directive.collector.StaticPropertyCollector
2626
import org.domaframework.doma.intellij.psi.SqlElClass
@@ -31,12 +31,14 @@ import org.jetbrains.kotlin.idea.base.util.module
3131
class StaticDirectiveHandler(
3232
originalFile: PsiElement,
3333
private val element: PsiElement,
34+
private val caretNextText: String,
3435
private val result: CompletionResultSet,
3536
private val bindText: String,
3637
) : DirectiveHandler(originalFile) {
3738
override fun directiveHandle(): Boolean {
3839
var handleResult = false
39-
if (element.prevSibling is SqlElStaticFieldAccessExpr) {
40+
41+
if (isNextStaticFieldAccess(element)) {
4042
handleResult = staticDirectiveHandler(element, result)
4143
}
4244
if (handleResult) return true
@@ -60,20 +62,30 @@ class StaticDirectiveHandler(
6062
return handleResult
6163
}
6264

65+
private fun isNextStaticFieldAccess(element: PsiElement): Boolean {
66+
val prev = PsiTreeUtil.prevLeaf(element)
67+
return element.prevSibling is SqlElStaticFieldAccessExpr ||
68+
(
69+
prev?.elementType == SqlTypes.AT_SIGN &&
70+
prev.parent is SqlElStaticFieldAccessExpr
71+
)
72+
}
73+
6374
private fun staticDirectiveHandler(
6475
element: PsiElement,
6576
result: CompletionResultSet,
6677
): Boolean {
6778
val clazzRef =
6879
PsiTreeUtil
6980
.getChildOfType(element.prevSibling, SqlElClass::class.java)
81+
?: PsiTreeUtil.getChildOfType(PsiTreeUtil.prevLeaf(element)?.parent, SqlElClass::class.java)
7082
val fqdn =
7183
PsiTreeUtil.getChildrenOfTypeAsList(clazzRef, PsiElement::class.java).joinToString("") { it.text }
7284

73-
val collector = StaticPropertyCollector(element, bindText)
85+
val collector = StaticPropertyCollector(element, caretNextText, bindText)
7486
val candidates = collector.collectCompletionSuggest(fqdn) ?: return false
7587
result.addAllElements(candidates.field)
76-
candidates.methods.map { m -> result.addElement(m) }
88+
candidates.methods.forEach { m -> result.addElement(m) }
7789
return true
7890
}
7991

@@ -93,7 +105,8 @@ class StaticDirectiveHandler(
93105
): Boolean {
94106
if (BindDirectiveUtil.getDirectiveType(element) == DirectiveType.BUILT_IN) {
95107
val prefix = getBindSearchWord(element, bindText)
96-
val collector = StaticBuildFunctionCollector(element.containingFile, prefix)
108+
val collector =
109+
FunctionCallCollector(element.containingFile, caretNextText, prefix)
97110
val candidates = collector.collect()
98111
candidates?.let { it1 -> result.addAllElements(it1) }
99112
return true

src/main/kotlin/org/domaframework/doma/intellij/common/sql/directive/StaticDirectiveHandlerData.kt

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,6 @@ package org.domaframework.doma.intellij.common.sql.directive
1818
import com.intellij.codeInsight.lookup.LookupElement
1919
import com.intellij.codeInsight.lookup.VariableLookupItem
2020
import com.intellij.icons.AllIcons
21-
import com.intellij.psi.PsiType
22-
23-
/**
24-
* Function information displayed with code completion for built-in functions
25-
*/
26-
data class DomaFunction(
27-
val name: String,
28-
val returnType: PsiType,
29-
val parameters: List<PsiType>,
30-
)
3121

3222
/**
3323
* Show parameters in code completion for fields and methods
Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ import com.intellij.psi.PsiModifier
2424
import org.domaframework.doma.intellij.common.CommonPathParameterUtil
2525
import org.domaframework.doma.intellij.common.config.DomaCompileConfigUtil
2626
import org.domaframework.doma.intellij.common.helper.ExpressionFunctionsHelper
27+
import org.domaframework.doma.intellij.common.util.SqlCompletionUtil.createMethodLookupElement
2728
import org.domaframework.doma.intellij.extension.getJavaClazz
2829
import org.jetbrains.kotlin.idea.base.util.module
2930

30-
class StaticBuildFunctionCollector(
31+
class FunctionCallCollector(
3132
private val file: PsiFile?,
33+
private val caretNextText: String,
3234
private val bind: String,
3335
) : StaticDirectiveHandlerCollector() {
3436
public override fun collect(): List<LookupElement>? {
@@ -44,7 +46,13 @@ class StaticBuildFunctionCollector(
4446
}
4547

4648
val customFunctionClassName =
47-
project?.let { DomaCompileConfigUtil.getConfigValue(it, resourcePaths, "doma.expr.functions") }
49+
project?.let {
50+
DomaCompileConfigUtil.getConfigValue(
51+
it,
52+
resourcePaths,
53+
"doma.expr.functions",
54+
)
55+
}
4856

4957
val expressionFunctionInterface =
5058
project?.let { ExpressionFunctionsHelper.setExpressionFunctionsInterface(it) }
@@ -62,21 +70,19 @@ class StaticBuildFunctionCollector(
6270
)
6371
}
6472

65-
if (functions.isEmpty()) {
66-
functions.addAll(
67-
expressionFunctionInterface.allMethods.filter {
68-
isPublicFunction(it)
69-
},
70-
)
71-
}
73+
functions.addAll(
74+
expressionFunctionInterface.allMethods.filter {
75+
isPublicFunction(it) && !functions.contains(it)
76+
},
77+
)
7278

7379
return functions
7480
.filter {
7581
it.name.startsWith(bind.substringAfter("@"))
7682
}.map {
7783
val parameters = it.parameterList.parameters.toList()
7884
LookupElementBuilder
79-
.create("${it.name}()")
85+
.create(createMethodLookupElement(caretNextText, it))
8086
.withPresentableText(it.name)
8187
.withTailText(
8288
"(${

src/main/kotlin/org/domaframework/doma/intellij/common/sql/directive/collector/StaticPropertyCollector.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ import com.intellij.psi.PsiElement
2222
import org.domaframework.doma.intellij.common.psi.PsiParentClass
2323
import org.domaframework.doma.intellij.common.psi.PsiStaticElement
2424
import org.domaframework.doma.intellij.common.sql.directive.CompletionSuggest
25+
import org.domaframework.doma.intellij.common.util.SqlCompletionUtil.createMethodLookupElement
2526
import org.domaframework.doma.intellij.extension.psi.psiClassType
2627

2728
class StaticPropertyCollector(
2829
private val element: PsiElement,
30+
private val caretNextText: String,
2931
private val bind: String,
3032
) : StaticDirectiveHandlerCollector() {
3133
public override fun collectCompletionSuggest(fqdn: String): CompletionSuggest? {
@@ -39,7 +41,7 @@ class StaticPropertyCollector(
3941
val methods =
4042
clazz.searchStaticMethod(bind)?.map { m ->
4143
LookupElementBuilder
42-
.create("${m.name}()")
44+
.create(createMethodLookupElement(caretNextText, m))
4345
.withPresentableText(m.name)
4446
.withTailText(m.parameterList.text, true)
4547
.withIcon(AllIcons.Nodes.Method)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ class ForDirectiveUtil {
225225
val classType = lastType.type as? PsiClassType
226226
val nestClass =
227227
if (classType != null &&
228-
PsiClassTypeUtil.Companion.isIterableType(
228+
PsiClassTypeUtil.isIterableType(
229229
classType,
230230
project,
231231
)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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.psi.PsiMethod
19+
20+
object SqlCompletionUtil {
21+
fun createMethodLookupElement(
22+
caretNextText: String,
23+
method: PsiMethod,
24+
): String =
25+
if (caretNextText == "(") {
26+
method.name
27+
} else {
28+
"${method.name}()"
29+
}
30+
}

src/main/kotlin/org/domaframework/doma/intellij/contributor/sql/provider/SqlParameterCompletionProvider.kt

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import org.domaframework.doma.intellij.common.sql.directive.DirectiveCompletion
4343
import org.domaframework.doma.intellij.common.sql.validator.result.ValidationCompleteResult
4444
import org.domaframework.doma.intellij.common.util.ForDirectiveUtil
4545
import org.domaframework.doma.intellij.common.util.PluginLoggerUtil
46+
import org.domaframework.doma.intellij.common.util.SqlCompletionUtil.createMethodLookupElement
4647
import org.domaframework.doma.intellij.extension.getJavaClazz
4748
import org.domaframework.doma.intellij.extension.psi.findNodeParent
4849
import org.domaframework.doma.intellij.extension.psi.findSelfBlocks
@@ -78,6 +79,11 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
7879
val startTime = System.nanoTime()
7980

8081
var isDirective = false
82+
val offset = parameters.editor.caretModel.currentCaret.offset
83+
val range =
84+
com.intellij.openapi.util
85+
.TextRange(offset, offset + 1)
86+
val caretNextText = parameters.editor.document.getText(range)
8187
try {
8288
val originalFile = parameters.originalFile
8389
val pos = parameters.originalPosition ?: return
@@ -86,7 +92,7 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
8692
.substringAfter("/*")
8793
.substringBefore("*/")
8894

89-
val handler = DirectiveCompletion(originalFile, bindText, pos, result)
95+
val handler = DirectiveCompletion(originalFile, bindText, pos, caretNextText, result)
9096
val directiveSymbols = listOf("%", "#", "^", "@")
9197
directiveSymbols.forEach {
9298
if (!isDirective) {
@@ -118,6 +124,7 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
118124
blockElements,
119125
pos,
120126
originalFile,
127+
caretNextText,
121128
result,
122129
)
123130
PluginLoggerUtil.countLogging(
@@ -268,6 +275,7 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
268275
elements: List<PsiElement>,
269276
position: PsiElement,
270277
originalFile: PsiFile,
278+
caretNextText: String,
271279
result: CompletionResultSet,
272280
) {
273281
val daoMethod = findDaoMethod(originalFile)
@@ -281,7 +289,7 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
281289
val topText = cleanString(getSearchElementText(top))
282290
val prevWord = PsiPatternUtil.getBindSearchWord(originalFile, elements.last(), " ")
283291
if (prevWord.startsWith("@") && prevWord.endsWith("@")) {
284-
setCompletionStaticFieldAccess(top, prevWord, topText, result)
292+
setCompletionStaticFieldAccess(top, prevWord, caretNextText, topText, result)
285293
return
286294
}
287295

@@ -298,7 +306,7 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
298306
val psiDaoMethod = PsiDaoMethod(project, daoMethod)
299307
if (topElementType == null) {
300308
isBatchAnnotation = psiDaoMethod.daoType.isBatchAnnotation()
301-
if (isFieldAccessByForItem(top, elements, searchText, isBatchAnnotation, result)) return
309+
if (isFieldAccessByForItem(top, elements, searchText, caretNextText, isBatchAnnotation, result)) return
302310
topElementType =
303311
getElementTypeByFieldAccess(originalFile, position, elements, daoMethod, result) ?: return
304312
}
@@ -309,6 +317,7 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
309317
isBatchAnnotation,
310318
elements,
311319
searchText,
320+
caretNextText,
312321
result,
313322
)
314323
}
@@ -399,6 +408,7 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
399408
): PsiClass? = top.project.getJavaClazz(fqdnGetter())
400409

401410
private fun setFieldsAndMethodsCompletionResultSet(
411+
caretNextText: String,
402412
fields: Array<PsiField>,
403413
methods: Array<PsiMethod>,
404414
result: CompletionResultSet,
@@ -407,7 +417,7 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
407417
methods.forEach { method ->
408418
val lookupElm =
409419
LookupElementBuilder
410-
.create("${method.name}()")
420+
.create(createMethodLookupElement(caretNextText, method))
411421
.withPresentableText(method.name)
412422
.withTailText(method.parameterList.text, true)
413423
.withTypeText(method.returnType?.presentableText ?: "")
@@ -422,6 +432,7 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
422432
top: PsiElement,
423433
elements: List<PsiElement>,
424434
searchWord: String,
435+
caretNextText: String,
425436
isBatchAnnotation: Boolean = false,
426437
result: CompletionResultSet,
427438
): Boolean {
@@ -448,6 +459,7 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
448459
dropLastIndex = 1,
449460
complete = { lastType ->
450461
setFieldsAndMethodsCompletionResultSet(
462+
caretNextText,
451463
lastType.searchField(searchWord)?.toTypedArray() ?: emptyArray(),
452464
lastType.searchMethod(searchWord)?.toTypedArray() ?: emptyArray(),
453465
result,
@@ -463,6 +475,7 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
463475
isBatchAnnotation: Boolean,
464476
elements: List<PsiElement>,
465477
searchWord: String,
478+
caretNextText: String,
466479
result: CompletionResultSet,
467480
) {
468481
var psiParentClass = PsiParentClass(topElementType)
@@ -477,6 +490,7 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
477490
dropLastIndex = 1,
478491
complete = { lastType ->
479492
setFieldsAndMethodsCompletionResultSet(
493+
caretNextText,
480494
lastType.searchField(searchWord)?.toTypedArray() ?: emptyArray(),
481495
lastType.searchMethod(searchWord)?.toTypedArray() ?: emptyArray(),
482496
result,
@@ -488,6 +502,7 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
488502
private fun setCompletionStaticFieldAccess(
489503
top: PsiElement,
490504
prevWord: String,
505+
caretNextText: String,
491506
topText: String,
492507
result: CompletionResultSet,
493508
) {
@@ -496,6 +511,6 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
496511
val matchMethod = clazz.searchStaticMethod(topText)
497512

498513
// When you enter here, it is the top element, so return static fields and methods.
499-
setFieldsAndMethodsCompletionResultSet(matchFields, matchMethod, result)
514+
setFieldsAndMethodsCompletionResultSet(caretNextText, matchFields, matchMethod, result)
500515
}
501516
}

0 commit comments

Comments
 (0)