|
16 | 16 | package org.domaframework.doma.intellij.common.sql.directive |
17 | 17 |
|
18 | 18 | import com.intellij.codeInsight.completion.CompletionResultSet |
19 | | -import com.intellij.codeInsight.lookup.LookupElement |
20 | | -import com.intellij.codeInsight.lookup.LookupElementBuilder |
21 | | -import com.intellij.codeInsight.lookup.VariableLookupItem |
| 19 | +import com.intellij.openapi.module.Module |
22 | 20 | import com.intellij.openapi.project.Project |
23 | 21 | import com.intellij.psi.PsiElement |
24 | | -import com.intellij.psi.PsiManager |
25 | | -import com.intellij.psi.PsiType |
26 | | -import com.intellij.psi.search.GlobalSearchScope |
27 | 22 | import com.intellij.psi.util.PsiTreeUtil |
28 | 23 | import com.intellij.psi.util.elementType |
29 | | -import org.domaframework.doma.intellij.common.psi.PsiParentClass |
30 | | -import org.domaframework.doma.intellij.common.psi.PsiStaticElement |
31 | | -import org.domaframework.doma.intellij.extension.psi.psiClassType |
| 24 | +import org.domaframework.doma.intellij.common.sql.directive.collector.StaticBuildFunctionCollector |
| 25 | +import org.domaframework.doma.intellij.common.sql.directive.collector.StaticClassPackageCollector |
| 26 | +import org.domaframework.doma.intellij.common.sql.directive.collector.StaticPropertyCollector |
32 | 27 | import org.domaframework.doma.intellij.psi.SqlElClass |
33 | 28 | import org.domaframework.doma.intellij.psi.SqlElStaticFieldAccessExpr |
34 | 29 | import org.domaframework.doma.intellij.psi.SqlTypes |
| 30 | +import org.jetbrains.kotlin.idea.base.util.module |
35 | 31 |
|
36 | 32 | class StaticDirectiveHandler( |
37 | | - private val originalFile: PsiElement, |
| 33 | + originalFile: PsiElement, |
38 | 34 | private val element: PsiElement, |
39 | 35 | private val result: CompletionResultSet, |
40 | 36 | private val bindText: String, |
41 | 37 | private val project: Project, |
42 | 38 | ) : DirectiveHandler(originalFile) { |
43 | | - /** |
44 | | - * Function information displayed with code completion for built-in functions |
45 | | - */ |
46 | | - data class DomaFunction( |
47 | | - val name: String, |
48 | | - val returnType: PsiType, |
49 | | - val parameters: List<PsiType>, |
50 | | - ) |
51 | | - |
52 | | - /** |
53 | | - * Show parameters in code completion for fields and methods |
54 | | - */ |
55 | | - data class CompletionSuggest( |
56 | | - val field: List<VariableLookupItem>, |
57 | | - val methods: List<LookupElement>, |
58 | | - ) |
59 | | - |
60 | 39 | override fun directiveHandle(): Boolean { |
61 | 40 | var handleResult = false |
62 | 41 | if (element.prevSibling is SqlElStaticFieldAccessExpr) { |
| 42 | + handleResult = staticDirectiveHandler(element, result) |
| 43 | + } |
| 44 | + if (handleResult) return true |
| 45 | + |
| 46 | + if (PsiTreeUtil.nextLeaf(element)?.elementType == SqlTypes.AT_SIGN || |
| 47 | + element.elementType == SqlTypes.AT_SIGN |
| 48 | + ) { |
| 49 | + val module = element.module ?: return false |
63 | 50 | handleResult = |
64 | | - staticDirectiveHandler(element, result) { fqdn, bind -> |
65 | | - val psiStaticElement = PsiStaticElement(fqdn, originalFile.containingFile) |
66 | | - val javaClass = |
67 | | - psiStaticElement.getRefClazz() ?: return@staticDirectiveHandler null |
68 | | - val parentClazz = PsiParentClass(javaClass.psiClassType) |
69 | | - parentClazz.let { clazz -> |
70 | | - val fields = |
71 | | - clazz.searchStaticField(bind)?.map { f -> VariableLookupItem(f) } |
72 | | - val methods = |
73 | | - clazz.searchStaticMethod(bind)?.map { m -> |
74 | | - LookupElementBuilder |
75 | | - .create("${m.name}()") |
76 | | - .withPresentableText(m.name) |
77 | | - .withTailText(m.parameterList.text, true) |
78 | | - .withTypeText(m.returnType?.presentableText ?: "") |
79 | | - } |
80 | | - CompletionSuggest(fields ?: emptyList(), methods ?: emptyList()) |
81 | | - } |
82 | | - } |
83 | | - } else if (element.prevSibling?.elementType == SqlTypes.AT_SIGN) { |
| 51 | + collectionModulePackages( |
| 52 | + module, |
| 53 | + result, |
| 54 | + ) |
| 55 | + } |
| 56 | + if (handleResult) return true |
| 57 | + |
| 58 | + if (element.prevSibling?.elementType == SqlTypes.AT_SIGN) { |
84 | 59 | // Built-in function completion |
85 | | - handleResult = |
86 | | - builtInDirectiveHandler(element, result) { bind -> |
87 | | - listOf( |
88 | | - DomaFunction( |
89 | | - "escape", |
90 | | - getJavaLangString(), |
91 | | - listOf( |
92 | | - getPsiTypeByClassName("java.lang.CharSequence"), |
93 | | - getPsiTypeByClassName("java.lang.Char"), |
94 | | - ), |
95 | | - ), |
96 | | - DomaFunction( |
97 | | - "prefix", |
98 | | - getJavaLangString(), |
99 | | - listOf( |
100 | | - getPsiTypeByClassName("java.lang.CharSequence"), |
101 | | - getPsiTypeByClassName("java.lang.Char"), |
102 | | - ), |
103 | | - ), |
104 | | - DomaFunction( |
105 | | - "infix", |
106 | | - getJavaLangString(), |
107 | | - listOf( |
108 | | - getPsiTypeByClassName("java.lang.CharSequence"), |
109 | | - getPsiTypeByClassName("java.lang.Char"), |
110 | | - ), |
111 | | - ), |
112 | | - DomaFunction( |
113 | | - "suffix", |
114 | | - getJavaLangString(), |
115 | | - listOf( |
116 | | - getPsiTypeByClassName("java.lang.CharSequence"), |
117 | | - getPsiTypeByClassName("java.lang.Char"), |
118 | | - ), |
119 | | - ), |
120 | | - DomaFunction( |
121 | | - "roundDownTimePart", |
122 | | - getPsiTypeByClassName("java.util.Date"), |
123 | | - listOf(getPsiTypeByClassName("java.util.Date")), |
124 | | - ), |
125 | | - DomaFunction( |
126 | | - "roundDownTimePart", |
127 | | - getPsiTypeByClassName("java.sql.Date"), |
128 | | - listOf(getPsiTypeByClassName("java.util.Date")), |
129 | | - ), |
130 | | - DomaFunction( |
131 | | - "roundDownTimePart", |
132 | | - getPsiTypeByClassName("java.sql.Timestamp"), |
133 | | - listOf(getPsiTypeByClassName("java.sql.Timestamp")), |
134 | | - ), |
135 | | - DomaFunction( |
136 | | - "roundDownTimePart", |
137 | | - getPsiTypeByClassName("java.time.LocalDateTime"), |
138 | | - listOf(getPsiTypeByClassName("java.time.LocalDateTime")), |
139 | | - ), |
140 | | - DomaFunction( |
141 | | - "roundUpTimePart", |
142 | | - getPsiTypeByClassName("java.util.Date"), |
143 | | - listOf(getPsiTypeByClassName("java.sql.Date")), |
144 | | - ), |
145 | | - DomaFunction( |
146 | | - "roundUpTimePart", |
147 | | - getPsiTypeByClassName("java.sql.Timestamp"), |
148 | | - listOf(getPsiTypeByClassName("java.sql.Timestamp")), |
149 | | - ), |
150 | | - DomaFunction( |
151 | | - "roundUpTimePart", |
152 | | - getPsiTypeByClassName("java.time.LocalDate"), |
153 | | - listOf(getPsiTypeByClassName("java.time.LocalDate")), |
154 | | - ), |
155 | | - DomaFunction( |
156 | | - "isEmpty", |
157 | | - getPsiTypeByClassName("boolean"), |
158 | | - listOf(getPsiTypeByClassName("java.lang.CharSequence")), |
159 | | - ), |
160 | | - DomaFunction( |
161 | | - "isNotEmpty", |
162 | | - getPsiTypeByClassName("boolean"), |
163 | | - listOf(getPsiTypeByClassName("java.lang.CharSequence")), |
164 | | - ), |
165 | | - DomaFunction( |
166 | | - "isBlank", |
167 | | - getPsiTypeByClassName("boolean"), |
168 | | - listOf(getPsiTypeByClassName("java.lang.CharSequence")), |
169 | | - ), |
170 | | - DomaFunction( |
171 | | - "isNotBlank", |
172 | | - getPsiTypeByClassName("boolean"), |
173 | | - listOf(getPsiTypeByClassName("java.lang.CharSequence")), |
174 | | - ), |
175 | | - ).filter { |
176 | | - it.name.startsWith(bind.substringAfter("@")) |
177 | | - }.map { |
178 | | - LookupElementBuilder |
179 | | - .create("${it.name}()") |
180 | | - .withPresentableText(it.name) |
181 | | - .withTailText( |
182 | | - "(${ |
183 | | - it.parameters.joinToString(",") { param -> |
184 | | - param.toString().replace("PsiType:", "") |
185 | | - } |
186 | | - })", |
187 | | - true, |
188 | | - ).withTypeText(it.returnType.presentableText) |
189 | | - } |
190 | | - } |
| 60 | + handleResult = builtInDirectiveHandler(element, result) |
191 | 61 | } |
192 | 62 | return handleResult |
193 | 63 | } |
194 | 64 |
|
195 | 65 | private fun staticDirectiveHandler( |
196 | 66 | element: PsiElement, |
197 | 67 | result: CompletionResultSet, |
198 | | - processor: (String, String) -> CompletionSuggest?, |
199 | 68 | ): Boolean { |
200 | 69 | val clazzRef = |
201 | 70 | PsiTreeUtil |
202 | 71 | .getChildOfType(element.prevSibling, SqlElClass::class.java) |
203 | 72 | val fqdn = |
204 | 73 | PsiTreeUtil.getChildrenOfTypeAsList(clazzRef, PsiElement::class.java).joinToString("") { it.text } |
205 | | - val candidates = processor(fqdn, bindText) ?: return false |
| 74 | + |
| 75 | + val collector = StaticPropertyCollector(element, bindText) |
| 76 | + val candidates = collector.collectCompletionSuggest(fqdn) ?: return false |
206 | 77 | result.addAllElements(candidates.field) |
207 | 78 | candidates.methods.map { m -> result.addElement(m) } |
208 | 79 | return true |
209 | 80 | } |
210 | 81 |
|
| 82 | + private fun collectionModulePackages( |
| 83 | + module: Module, |
| 84 | + result: CompletionResultSet, |
| 85 | + ): Boolean { |
| 86 | + val collector = StaticClassPackageCollector(element, module) |
| 87 | + val candidates = collector.collect() ?: return false |
| 88 | + result.addAllElements(candidates) |
| 89 | + return true |
| 90 | + } |
| 91 | + |
211 | 92 | private fun builtInDirectiveHandler( |
212 | 93 | element: PsiElement, |
213 | 94 | result: CompletionResultSet, |
214 | | - processor: (String) -> List<LookupElement>?, |
215 | 95 | ): Boolean { |
216 | 96 | if (BindDirectiveUtil.getDirectiveType(element) == DirectiveType.BUILT_IN) { |
217 | | - val prefix = getBindSearchWord(element, "@") |
218 | | - val candidates = processor(prefix) |
| 97 | + val prefix = getBindSearchWord(element, bindText) |
| 98 | + val collector = StaticBuildFunctionCollector(project, prefix) |
| 99 | + val candidates = collector.collect() |
219 | 100 | candidates?.let { it1 -> result.addAllElements(it1) } |
220 | 101 | return true |
221 | 102 | } |
222 | 103 | return false |
223 | 104 | } |
224 | | - |
225 | | - private fun getJavaLangString(): PsiType = |
226 | | - PsiType.getJavaLangString( |
227 | | - PsiManager.getInstance(project), |
228 | | - GlobalSearchScope.allScope(project), |
229 | | - ) |
230 | | - |
231 | | - private fun getPsiTypeByClassName(className: String): PsiType = |
232 | | - PsiType.getTypeByName(className, project, GlobalSearchScope.allScope(project)) |
233 | 105 | } |
0 commit comments