Skip to content

Commit 56341a0

Browse files
committed
Document generation process organized into classes
1 parent 53cbaf9 commit 56341a0

File tree

4 files changed

+214
-129
lines changed

4 files changed

+214
-129
lines changed

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

Lines changed: 17 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,10 @@
1616
package org.domaframework.doma.intellij.document
1717

1818
import com.intellij.lang.documentation.AbstractDocumentationProvider
19-
import com.intellij.openapi.project.Project
2019
import com.intellij.psi.PsiElement
21-
import com.intellij.psi.PsiFile
2220
import com.intellij.psi.util.PsiTreeUtil
23-
import org.domaframework.doma.intellij.common.dao.findDaoMethod
24-
import org.domaframework.doma.intellij.common.psi.PsiDaoMethod
25-
import org.domaframework.doma.intellij.common.psi.PsiParentClass
26-
import org.domaframework.doma.intellij.common.psi.PsiStaticElement
27-
import org.domaframework.doma.intellij.common.sql.foritem.ForItem
28-
import org.domaframework.doma.intellij.common.util.ForDirectiveUtil
29-
import org.domaframework.doma.intellij.extension.expr.accessElements
30-
import org.domaframework.doma.intellij.extension.expr.accessElementsPrevOriginalElement
31-
import org.domaframework.doma.intellij.extension.psi.findParameter
32-
import org.domaframework.doma.intellij.extension.psi.getForItem
33-
import org.domaframework.doma.intellij.extension.psi.psiClassType
34-
import org.domaframework.doma.intellij.psi.SqlElClass
35-
import org.domaframework.doma.intellij.psi.SqlElFieldAccessExpr
21+
import org.domaframework.doma.intellij.document.generator.DocumentDaoParameterGenerator
22+
import org.domaframework.doma.intellij.document.generator.DocumentStaticFieldGenerator
3623
import org.domaframework.doma.intellij.psi.SqlElIdExpr
3724
import org.domaframework.doma.intellij.psi.SqlElStaticFieldAccessExpr
3825
import org.domaframework.doma.intellij.psi.SqlTypes
@@ -56,93 +43,26 @@ class ForItemElementDocumentationProvider : AbstractDocumentationProvider() {
5643

5744
val staticFieldAccessExpr =
5845
PsiTreeUtil.getParentOfType(originalElement, SqlElStaticFieldAccessExpr::class.java)
59-
if (staticFieldAccessExpr != null) {
60-
generateStaticFieldDocument(
61-
staticFieldAccessExpr,
62-
file,
63-
originalElement,
64-
project,
65-
result,
66-
)
67-
} else {
68-
generateDaoFieldAccessDocument(originalElement, project, result)
69-
}
70-
return result.joinToString("\n")
71-
}
72-
73-
private fun generateDaoFieldAccessDocument(
74-
originalElement: PsiElement,
75-
project: Project,
76-
result: MutableList<String?>,
77-
) {
78-
var topParentType: PsiParentClass? = null
79-
val selfSkip = isSelfSkip(originalElement)
80-
val forDirectives = ForDirectiveUtil.getForDirectiveBlocks(originalElement, selfSkip)
81-
val fieldAccessExpr =
82-
PsiTreeUtil.getParentOfType(
83-
originalElement,
84-
SqlElFieldAccessExpr::class.java,
85-
)
86-
val fieldAccessBlocks =
87-
fieldAccessExpr?.accessElementsPrevOriginalElement(originalElement.textOffset)
88-
val searchElement = fieldAccessBlocks?.firstOrNull() ?: originalElement
89-
90-
var isBatchAnnotation = false
91-
if (ForDirectiveUtil.findForItem(searchElement, forDirectives = forDirectives) != null) {
92-
topParentType = ForDirectiveUtil.getForDirectiveItemClassType(project, forDirectives)
93-
} else {
94-
val daoMethod = findDaoMethod(originalElement.containingFile) ?: return
95-
val param = daoMethod.findParameter(originalElement.text) ?: return
96-
isBatchAnnotation = PsiDaoMethod(project, daoMethod).daoType.isBatchAnnotation()
97-
topParentType = PsiParentClass(param.type)
98-
}
99-
if (fieldAccessExpr != null && fieldAccessBlocks != null) {
100-
topParentType?.let {
101-
ForDirectiveUtil.getFieldAccessLastPropertyClassType(
102-
fieldAccessBlocks,
46+
val generator =
47+
if (staticFieldAccessExpr != null) {
48+
DocumentStaticFieldGenerator(
49+
originalElement,
50+
project,
51+
result,
52+
staticFieldAccessExpr,
53+
file,
54+
)
55+
} else {
56+
DocumentDaoParameterGenerator(
57+
originalElement,
10358
project,
104-
it,
105-
isBatchAnnotation = isBatchAnnotation,
106-
complete = { lastType ->
107-
result.add("${generateTypeLink(lastType)} ${originalElement.text}")
108-
},
59+
result,
10960
)
11061
}
111-
return
112-
}
113-
result.add("${generateTypeLink(topParentType)} ${originalElement.text}")
114-
}
115-
116-
private fun generateStaticFieldDocument(
117-
staticFieldAccessExpr: SqlElStaticFieldAccessExpr,
118-
file: PsiFile,
119-
originalElement: PsiElement,
120-
project: Project,
121-
result: MutableList<String?>,
122-
) {
123-
val fieldAccessBlocks = staticFieldAccessExpr.accessElements
124-
val staticElement = PsiStaticElement(fieldAccessBlocks, file)
125-
val referenceClass = staticElement.getRefClazz() ?: return
126-
if (PsiTreeUtil.getParentOfType(originalElement, SqlElClass::class.java) != null) {
127-
val clazzType = PsiParentClass(referenceClass.psiClassType)
128-
result.add("${generateTypeLink(clazzType)} ${originalElement.text}")
129-
return
130-
}
13162

132-
ForDirectiveUtil.getFieldAccessLastPropertyClassType(
133-
fieldAccessBlocks.filter { it.textOffset <= originalElement.textOffset },
134-
project,
135-
PsiParentClass(referenceClass.psiClassType),
136-
complete = { lastType ->
137-
result.add("${generateTypeLink(lastType)} ${originalElement.text}")
138-
},
139-
)
140-
}
63+
generator.generateDocument()
14164

142-
private fun isSelfSkip(targetElement: PsiElement): Boolean {
143-
val forItem = ForItem(targetElement)
144-
val forDirectiveExpr = forItem.getParentForDirectiveExpr()
145-
return !(forDirectiveExpr != null && forDirectiveExpr.getForItem()?.textOffset == targetElement.textOffset)
65+
return result.joinToString("\n")
14666
}
14767

14868
override fun generateHoverDoc(
@@ -159,36 +79,4 @@ class ForItemElementDocumentationProvider : AbstractDocumentationProvider() {
15979
result.add(typeDocument)
16080
return result.joinToString("\n")
16181
}
162-
163-
private fun generateTypeLink(parentClass: PsiParentClass?): String {
164-
if (parentClass?.type != null) {
165-
return generateTypeLinkFromCanonicalText(parentClass.type.canonicalText)
166-
}
167-
return ""
168-
}
169-
170-
private fun generateTypeLinkFromCanonicalText(canonicalText: String): String {
171-
val regex = Regex("([a-zA-Z0-9_]+\\.)*([a-zA-Z0-9_]+)")
172-
val result = StringBuilder()
173-
var lastIndex = 0
174-
175-
for (match in regex.findAll(canonicalText)) {
176-
val fullMatch = match.value
177-
val typeName = match.groups[2]?.value ?: fullMatch
178-
val startIndex = match.range.first
179-
val endIndex = match.range.last + 1
180-
181-
if (lastIndex < startIndex) {
182-
result.append(canonicalText.substring(lastIndex, startIndex))
183-
}
184-
result.append("<a href=\"psi_element://$fullMatch\">$typeName</a>")
185-
lastIndex = endIndex
186-
}
187-
188-
if (lastIndex < canonicalText.length) {
189-
result.append(canonicalText.substring(lastIndex))
190-
}
191-
192-
return result.toString()
193-
}
19482
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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.document.generator
17+
18+
import com.intellij.openapi.project.Project
19+
import com.intellij.psi.PsiElement
20+
import com.intellij.psi.util.PsiTreeUtil
21+
import org.domaframework.doma.intellij.common.dao.findDaoMethod
22+
import org.domaframework.doma.intellij.common.psi.PsiDaoMethod
23+
import org.domaframework.doma.intellij.common.psi.PsiParentClass
24+
import org.domaframework.doma.intellij.common.util.ForDirectiveUtil
25+
import org.domaframework.doma.intellij.extension.expr.accessElementsPrevOriginalElement
26+
import org.domaframework.doma.intellij.extension.psi.findParameter
27+
import org.domaframework.doma.intellij.psi.SqlElFieldAccessExpr
28+
29+
class DocumentDaoParameterGenerator(
30+
val originalElement: PsiElement,
31+
val project: Project,
32+
val result: MutableList<String?>,
33+
) : DocumentGenerator(originalElement, project, result) {
34+
override fun generateDocument() {
35+
var topParentType: PsiParentClass? = null
36+
val selfSkip = isSelfSkip(originalElement)
37+
val forDirectives = ForDirectiveUtil.getForDirectiveBlocks(originalElement, selfSkip)
38+
val fieldAccessExpr =
39+
PsiTreeUtil.getParentOfType(
40+
originalElement,
41+
SqlElFieldAccessExpr::class.java,
42+
)
43+
val fieldAccessBlocks =
44+
fieldAccessExpr?.accessElementsPrevOriginalElement(originalElement.textOffset)
45+
val searchElement = fieldAccessBlocks?.firstOrNull() ?: originalElement
46+
47+
var isBatchAnnotation = false
48+
if (ForDirectiveUtil.findForItem(searchElement, forDirectives = forDirectives) != null) {
49+
topParentType = ForDirectiveUtil.getForDirectiveItemClassType(project, forDirectives)
50+
} else {
51+
val daoMethod = findDaoMethod(originalElement.containingFile) ?: return
52+
val param = daoMethod.findParameter(originalElement.text) ?: return
53+
isBatchAnnotation = PsiDaoMethod(project, daoMethod).daoType.isBatchAnnotation()
54+
topParentType = PsiParentClass(param.type)
55+
}
56+
57+
if (fieldAccessExpr != null && fieldAccessBlocks != null) {
58+
topParentType?.let {
59+
ForDirectiveUtil.getFieldAccessLastPropertyClassType(
60+
fieldAccessBlocks,
61+
project,
62+
it,
63+
isBatchAnnotation = isBatchAnnotation,
64+
complete = { lastType ->
65+
result.add("${generateTypeLink(lastType)} ${originalElement.text}")
66+
},
67+
)
68+
}
69+
return
70+
}
71+
result.add("${generateTypeLink(topParentType)} ${originalElement.text}")
72+
}
73+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
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.document.generator
17+
18+
import com.intellij.openapi.project.Project
19+
import com.intellij.psi.PsiElement
20+
import org.domaframework.doma.intellij.common.psi.PsiParentClass
21+
import org.domaframework.doma.intellij.common.sql.foritem.ForItem
22+
import org.domaframework.doma.intellij.extension.psi.getForItem
23+
24+
abstract class DocumentGenerator(
25+
originalElement: PsiElement?,
26+
project: Project,
27+
result: MutableList<String?>,
28+
) {
29+
abstract fun generateDocument()
30+
31+
protected fun isSelfSkip(targetElement: PsiElement): Boolean {
32+
val forItem = ForItem(targetElement)
33+
val forDirectiveExpr = forItem.getParentForDirectiveExpr()
34+
return !(forDirectiveExpr != null && forDirectiveExpr.getForItem()?.textOffset == targetElement.textOffset)
35+
}
36+
37+
protected fun generateTypeLink(parentClass: PsiParentClass?): String {
38+
if (parentClass?.type != null) {
39+
return generateTypeLinkFromCanonicalText(parentClass.type.canonicalText)
40+
}
41+
return ""
42+
}
43+
44+
private fun generateTypeLinkFromCanonicalText(canonicalText: String): String {
45+
val regex = Regex("([a-zA-Z0-9_]+\\.)*([a-zA-Z0-9_]+)")
46+
val result = StringBuilder()
47+
var lastIndex = 0
48+
49+
for (match in regex.findAll(canonicalText)) {
50+
val fullMatch = match.value
51+
val typeName = match.groups[2]?.value ?: fullMatch
52+
val startIndex = match.range.first
53+
val endIndex = match.range.last + 1
54+
55+
if (lastIndex < startIndex) {
56+
result.append(canonicalText.substring(lastIndex, startIndex))
57+
}
58+
result.append("<a href=\"psi_element://$fullMatch\">$typeName</a>")
59+
lastIndex = endIndex
60+
}
61+
62+
if (lastIndex < canonicalText.length) {
63+
result.append(canonicalText.substring(lastIndex))
64+
}
65+
66+
return result.toString()
67+
}
68+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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.document.generator
17+
18+
import com.intellij.openapi.project.Project
19+
import com.intellij.psi.PsiElement
20+
import com.intellij.psi.PsiFile
21+
import com.intellij.psi.util.PsiTreeUtil
22+
import org.domaframework.doma.intellij.common.psi.PsiParentClass
23+
import org.domaframework.doma.intellij.common.psi.PsiStaticElement
24+
import org.domaframework.doma.intellij.common.util.ForDirectiveUtil
25+
import org.domaframework.doma.intellij.extension.expr.accessElements
26+
import org.domaframework.doma.intellij.extension.psi.psiClassType
27+
import org.domaframework.doma.intellij.psi.SqlElClass
28+
import org.domaframework.doma.intellij.psi.SqlElStaticFieldAccessExpr
29+
30+
class DocumentStaticFieldGenerator(
31+
val originalElement: PsiElement,
32+
val project: Project,
33+
val result: MutableList<String?>,
34+
val staticFieldAccessExpr: SqlElStaticFieldAccessExpr,
35+
val file: PsiFile,
36+
) : DocumentGenerator(originalElement, project, result) {
37+
override fun generateDocument() {
38+
val fieldAccessBlocks = staticFieldAccessExpr.accessElements
39+
val staticElement = PsiStaticElement(fieldAccessBlocks, file)
40+
val referenceClass = staticElement.getRefClazz() ?: return
41+
if (PsiTreeUtil.getParentOfType(originalElement, SqlElClass::class.java) != null) {
42+
val clazzType = PsiParentClass(referenceClass.psiClassType)
43+
result.add("${generateTypeLink(clazzType)} ${originalElement.text}")
44+
return
45+
}
46+
47+
ForDirectiveUtil.getFieldAccessLastPropertyClassType(
48+
fieldAccessBlocks.filter { it.textOffset <= originalElement.textOffset },
49+
project,
50+
PsiParentClass(referenceClass.psiClassType),
51+
complete = { lastType ->
52+
result.add("${generateTypeLink(lastType)} ${originalElement.text}")
53+
},
54+
)
55+
}
56+
}

0 commit comments

Comments
 (0)