Skip to content

Commit bef9d08

Browse files
committed
feat: use own indexers
1 parent 69ffadc commit bef9d08

File tree

12 files changed

+324
-20
lines changed

12 files changed

+324
-20
lines changed

CONTRIBUTING.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ When implementing a feature that should work across multiple languages (e.g., Ac
4141
val ACTIVITY_EP = ExtensionPointName.create<Activity>("com.github.xepozz.temporal.activity")
4242

4343
fun getActivities(project: Project): List<ActivityModel> {
44-
return ACTIVITY_EP.extensionList.flatMap { it.getActivities(project) }
44+
return ACTIVITY_EP.lazyDumbAwareExtensions(project).flatMap { it.getActivities(project) }.toList()
4545
}
4646
}
4747
}
@@ -82,7 +82,7 @@ When implementing a feature that should work across multiple languages (e.g., Ac
8282
## Coding Standards
8383

8484
- **Kotlin First**: All new code should be written in Kotlin.
85-
- **Performance**: Use `CachedValue` and `DumbService.isDumb()` checks where appropriate.
85+
- **Performance**: Use `CachedValue` and `DumbService.isDumb()` checks where appropriate. Use `lazyDumbAwareExtensions(project)` instead of `extensionList` when accessing Extension Points to ensure better performance and compatibility with dumb mode.
8686
- **Consistency**: Follow the existing package structure. For example, if a feature is implemented for PHP in `languages.php.navigation`, any future language implementations should follow the same sub-package structure (e.g., `languages.go.navigation`).
8787
- **Naming**:
8888
- Extension Points should **not** end with `EP`. They should represent the entity or feature (e.g., `ActivityCompletion`, `Workflow`).

src/main/kotlin/com/github/xepozz/temporal/common/extensionPoints/Activity.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.github.xepozz.temporal.common.extensionPoints
22

33
import com.intellij.openapi.extensions.ExtensionPointName
44
import com.intellij.openapi.project.Project
5+
import com.intellij.openapi.project.lazyDumbAwareExtensions
56
import com.github.xepozz.temporal.common.model.Activity as ActivityModel
67

78
interface Activity {
@@ -11,7 +12,7 @@ interface Activity {
1112
val ACTIVITY_EP = ExtensionPointName.create<Activity>("com.github.xepozz.temporal.activity")
1213

1314
fun getActivities(project: Project): List<ActivityModel> {
14-
return ACTIVITY_EP.extensionList.flatMap { it.getActivities(project) }
15+
return ACTIVITY_EP.lazyDumbAwareExtensions(project).flatMap { it.getActivities(project) }.toList()
1516
}
1617
}
1718
}

src/main/kotlin/com/github/xepozz/temporal/common/extensionPoints/Workflow.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.github.xepozz.temporal.common.extensionPoints
22

33
import com.intellij.openapi.extensions.ExtensionPointName
44
import com.intellij.openapi.project.Project
5+
import com.intellij.openapi.project.lazyDumbAwareExtensions
56
import com.github.xepozz.temporal.common.model.Workflow as WorkflowModel
67

78
interface Workflow {
@@ -11,7 +12,7 @@ interface Workflow {
1112
val WORKFLOW_EP = ExtensionPointName.create<Workflow>("com.github.xepozz.temporal.workflow")
1213

1314
fun getWorkflows(project: Project): List<WorkflowModel> {
14-
return WORKFLOW_EP.extensionList.flatMap { it.getWorkflows(project) }
15+
return WORKFLOW_EP.lazyDumbAwareExtensions(project).flatMap { it.getWorkflows(project) }.toList()
1516
}
1617
}
1718
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.github.xepozz.temporal.common.index
2+
3+
import com.intellij.util.indexing.DataIndexer
4+
import com.intellij.util.indexing.FileBasedIndex
5+
import com.intellij.util.indexing.FileBasedIndexExtension
6+
import com.intellij.util.indexing.FileContent
7+
import com.intellij.util.indexing.ID
8+
import com.intellij.util.io.DataExternalizer
9+
import com.intellij.util.io.EnumeratorStringDescriptor
10+
11+
abstract class AbstractIndex<T : Any> : FileBasedIndexExtension<String, T>() {
12+
abstract override fun getName(): ID<String, T>
13+
14+
abstract override fun getInputFilter(): FileBasedIndex.InputFilter
15+
16+
override fun dependsOnFileContent() = true
17+
18+
abstract override fun getIndexer(): DataIndexer<String, T, FileContent>
19+
20+
override fun getKeyDescriptor() = EnumeratorStringDescriptor.INSTANCE
21+
22+
abstract override fun getValueExternalizer(): DataExternalizer<T>
23+
24+
override fun getVersion() = 1
25+
}

src/main/kotlin/com/github/xepozz/temporal/languages/php/TemporalClasses.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ package com.github.xepozz.temporal.languages.php
22

33
object TemporalClasses {
44
const val ACTIVITY = "\\Temporal\\Activity\\ActivityInterface"
5+
const val ACTIVITY_METHOD = "\\Temporal\\Activity\\ActivityMethod"
56
const val WORKFLOW = "\\Temporal\\Workflow\\WorkflowInterface"
7+
const val WORKFLOW_METHOD = "\\Temporal\\Workflow\\WorkflowMethod"
8+
const val WORKFLOW_INIT = "\\Temporal\\Workflow\\WorkflowInit"
9+
const val UPDATE_VALIDATOR_METHOD = "\\Temporal\\Workflow\\UpdateValidatorMethod"
10+
const val UPDATE_METHOD = "\\Temporal\\Workflow\\UpdateMethod"
611
const val SIGNAL_METHOD = "\\Temporal\\Workflow\\SignalMethod"
12+
const val QUERY_METHOD = "\\Temporal\\Workflow\\QueryMethod"
713
const val CHILD_WORKFLOW_STUB = "\\Temporal\\Workflow\\ChildWorkflowStubInterface"
814
}
Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,65 @@
11
package com.github.xepozz.temporal.languages.php.endpoints
22

33
import com.github.xepozz.temporal.common.extensionPoints.Activity
4-
import com.github.xepozz.temporal.languages.php.TemporalClasses
5-
import com.github.xepozz.temporal.languages.php.hasAttribute
4+
import com.github.xepozz.temporal.languages.php.index.PhpActivityClassIndex
5+
import com.github.xepozz.temporal.languages.php.index.PhpActivityMethodIndex
66
import com.intellij.openapi.project.Project
77
import com.intellij.psi.SmartPointerManager
8+
import com.intellij.util.indexing.FileBasedIndex
89
import com.jetbrains.php.PhpIndex
910
import com.github.xepozz.temporal.common.model.Activity as ActivityModel
1011

1112
class PhpActivity : Activity {
1213
override fun getActivities(project: Project): List<ActivityModel> {
1314
val phpIndex = PhpIndex.getInstance(project)
1415
val smartPointerManager = SmartPointerManager.getInstance(project)
16+
val results = mutableListOf<ActivityModel>()
1517

16-
return phpIndex.getAllClassNames(null).flatMap { name ->
17-
phpIndex.getClassesByName(name)
18-
.filter { it.hasAttribute(TemporalClasses.ACTIVITY) }
19-
.map {
18+
val classFqns = mutableSetOf<String>()
19+
FileBasedIndex.getInstance().processAllKeys(PhpActivityClassIndex.NAME, { key ->
20+
classFqns.add(key)
21+
true
22+
}, project)
23+
24+
classFqns.forEach { fqn ->
25+
phpIndex.getClassesByFQN(fqn).forEach { phpClass ->
26+
results.add(
2027
ActivityModel(
21-
id = it.name,
28+
id = phpClass.name,
2229
language = "PHP",
23-
psiAnchor = smartPointerManager.createSmartPsiElementPointer(it),
30+
psiAnchor = smartPointerManager.createSmartPsiElementPointer(phpClass),
2431
parameters = emptyList()
2532
)
33+
)
34+
}
35+
}
36+
37+
val methodKeys = mutableSetOf<String>()
38+
FileBasedIndex.getInstance().processAllKeys(PhpActivityMethodIndex.NAME, { key ->
39+
methodKeys.add(key)
40+
true
41+
}, project)
42+
43+
methodKeys.forEach { key ->
44+
val parts = key.split("::")
45+
if (parts.size == 2) {
46+
val classFqn = parts[0]
47+
val methodName = parts[1]
48+
phpIndex.getClassesByFQN(classFqn).forEach { phpClass ->
49+
phpClass.methods.find { it.name == methodName }?.let { method ->
50+
results.add(
51+
ActivityModel(
52+
id = "$methodName (${phpClass.name})",
53+
language = "PHP",
54+
psiAnchor = smartPointerManager.createSmartPsiElementPointer(method),
55+
parameters = emptyList()
56+
)
57+
)
58+
}
2659
}
60+
}
2761
}
62+
63+
return results
2864
}
2965
}
Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,65 @@
11
package com.github.xepozz.temporal.languages.php.endpoints
22

33
import com.github.xepozz.temporal.common.extensionPoints.Workflow
4-
import com.github.xepozz.temporal.languages.php.TemporalClasses
5-
import com.github.xepozz.temporal.languages.php.hasAttribute
4+
import com.github.xepozz.temporal.languages.php.index.PhpWorkflowClassIndex
5+
import com.github.xepozz.temporal.languages.php.index.PhpWorkflowMethodIndex
66
import com.intellij.openapi.project.Project
77
import com.intellij.psi.SmartPointerManager
8+
import com.intellij.util.indexing.FileBasedIndex
89
import com.jetbrains.php.PhpIndex
910
import com.github.xepozz.temporal.common.model.Workflow as WorkflowModel
1011

1112
class PhpWorkflow : Workflow {
1213
override fun getWorkflows(project: Project): List<WorkflowModel> {
1314
val phpIndex = PhpIndex.getInstance(project)
1415
val smartPointerManager = SmartPointerManager.getInstance(project)
15-
return phpIndex.getAllClassNames(null).flatMap { name ->
16-
phpIndex.getClassesByName(name)
17-
.filter { it.hasAttribute(TemporalClasses.WORKFLOW) }
18-
.map {
16+
val results = mutableListOf<WorkflowModel>()
17+
18+
val classFqns = mutableSetOf<String>()
19+
FileBasedIndex.getInstance().processAllKeys(PhpWorkflowClassIndex.NAME, { key ->
20+
classFqns.add(key)
21+
true
22+
}, project)
23+
24+
classFqns.forEach { fqn ->
25+
phpIndex.getClassesByFQN(fqn).forEach { phpClass ->
26+
results.add(
1927
WorkflowModel(
20-
id = it.name,
28+
id = phpClass.name,
2129
language = "PHP",
22-
psiAnchor = smartPointerManager.createSmartPsiElementPointer(it),
30+
psiAnchor = smartPointerManager.createSmartPsiElementPointer(phpClass),
2331
parameters = emptyList()
2432
)
33+
)
34+
}
35+
}
36+
37+
val methodKeys = mutableSetOf<String>()
38+
FileBasedIndex.getInstance().processAllKeys(PhpWorkflowMethodIndex.NAME, { key ->
39+
methodKeys.add(key)
40+
true
41+
}, project)
42+
43+
methodKeys.forEach { key ->
44+
val parts = key.split("::")
45+
if (parts.size == 2) {
46+
val classFqn = parts[0]
47+
val methodName = parts[1]
48+
phpIndex.getClassesByFQN(classFqn).forEach { phpClass ->
49+
phpClass.methods.find { it.name == methodName }?.let { method ->
50+
results.add(
51+
WorkflowModel(
52+
id = "$methodName (${phpClass.name})",
53+
language = "PHP",
54+
psiAnchor = smartPointerManager.createSmartPsiElementPointer(method),
55+
parameters = emptyList()
56+
)
57+
)
58+
}
2559
}
60+
}
2661
}
62+
63+
return results
2764
}
2865
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.github.xepozz.temporal.languages.php.index
2+
3+
import com.github.xepozz.temporal.common.index.AbstractIndex
4+
import com.github.xepozz.temporal.languages.php.TemporalClasses
5+
import com.github.xepozz.temporal.languages.php.hasAttribute
6+
import com.intellij.psi.util.PsiTreeUtil
7+
import com.intellij.util.indexing.DataIndexer
8+
import com.intellij.util.indexing.FileBasedIndex
9+
import com.intellij.util.indexing.FileContent
10+
import com.intellij.util.indexing.ID
11+
import com.intellij.util.io.DataExternalizer
12+
import com.intellij.util.io.EnumeratorStringDescriptor
13+
import com.jetbrains.php.lang.PhpFileType
14+
import com.jetbrains.php.lang.psi.PhpFile
15+
import com.jetbrains.php.lang.psi.elements.PhpClass
16+
17+
class PhpActivityClassIndex : AbstractIndex<String>() {
18+
companion object {
19+
val NAME = ID.create<String, String>("temporal.activity.classes")
20+
}
21+
22+
override fun getName(): ID<String, String> = NAME
23+
24+
override fun getIndexer(): DataIndexer<String, String, FileContent> {
25+
return DataIndexer { fileContent ->
26+
val phpFile = fileContent.psiFile as? PhpFile ?: return@DataIndexer emptyMap()
27+
val result = mutableMapOf<String, String>()
28+
val classes = PsiTreeUtil.findChildrenOfType(phpFile, PhpClass::class.java)
29+
for (phpClass in classes) {
30+
if (phpClass.hasAttribute(TemporalClasses.ACTIVITY)) {
31+
val fqn = phpClass.fqn
32+
result[fqn] = fqn
33+
}
34+
}
35+
result
36+
}
37+
}
38+
39+
override fun getInputFilter(): FileBasedIndex.InputFilter {
40+
return FileBasedIndex.InputFilter { file -> file.fileType == PhpFileType.INSTANCE }
41+
}
42+
43+
override fun getValueExternalizer(): DataExternalizer<String> = EnumeratorStringDescriptor.INSTANCE
44+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.github.xepozz.temporal.languages.php.index
2+
3+
import com.github.xepozz.temporal.common.index.AbstractIndex
4+
import com.github.xepozz.temporal.languages.php.TemporalClasses
5+
import com.github.xepozz.temporal.languages.php.hasAttribute
6+
import com.intellij.psi.util.PsiTreeUtil
7+
import com.intellij.util.indexing.DataIndexer
8+
import com.intellij.util.indexing.FileBasedIndex
9+
import com.intellij.util.indexing.FileContent
10+
import com.intellij.util.indexing.ID
11+
import com.intellij.util.io.DataExternalizer
12+
import com.intellij.util.io.EnumeratorStringDescriptor
13+
import com.jetbrains.php.lang.PhpFileType
14+
import com.jetbrains.php.lang.psi.PhpFile
15+
import com.jetbrains.php.lang.psi.elements.PhpClass
16+
17+
class PhpActivityMethodIndex : AbstractIndex<String>() {
18+
companion object {
19+
val NAME = ID.create<String, String>("temporal.activity.methods")
20+
}
21+
22+
override fun getName(): ID<String, String> = NAME
23+
24+
override fun getIndexer(): DataIndexer<String, String, FileContent> {
25+
return DataIndexer { fileContent ->
26+
val phpFile = fileContent.psiFile as? PhpFile ?: return@DataIndexer emptyMap()
27+
val result = mutableMapOf<String, String>()
28+
val classes = PsiTreeUtil.findChildrenOfType(phpFile, PhpClass::class.java)
29+
for (phpClass in classes) {
30+
val classFqn = phpClass.fqn
31+
for (method in phpClass.methods) {
32+
if (method.hasAttribute(TemporalClasses.ACTIVITY_METHOD)) {
33+
result["$classFqn::${method.name}"] = TemporalClasses.ACTIVITY_METHOD
34+
}
35+
}
36+
}
37+
result
38+
}
39+
}
40+
41+
override fun getInputFilter(): FileBasedIndex.InputFilter {
42+
return FileBasedIndex.InputFilter { file -> file.fileType == PhpFileType.INSTANCE }
43+
}
44+
45+
override fun getValueExternalizer(): DataExternalizer<String> = EnumeratorStringDescriptor.INSTANCE
46+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.github.xepozz.temporal.languages.php.index
2+
3+
import com.github.xepozz.temporal.common.index.AbstractIndex
4+
import com.github.xepozz.temporal.languages.php.TemporalClasses
5+
import com.github.xepozz.temporal.languages.php.hasAttribute
6+
import com.intellij.psi.util.PsiTreeUtil
7+
import com.intellij.util.indexing.DataIndexer
8+
import com.intellij.util.indexing.FileBasedIndex
9+
import com.intellij.util.indexing.FileContent
10+
import com.intellij.util.indexing.ID
11+
import com.intellij.util.io.DataExternalizer
12+
import com.intellij.util.io.EnumeratorStringDescriptor
13+
import com.jetbrains.php.lang.PhpFileType
14+
import com.jetbrains.php.lang.psi.PhpFile
15+
import com.jetbrains.php.lang.psi.elements.PhpClass
16+
17+
class PhpWorkflowClassIndex : AbstractIndex<String>() {
18+
companion object {
19+
val NAME = ID.create<String, String>("temporal.workflow.classes")
20+
}
21+
22+
override fun getName(): ID<String, String> = NAME
23+
24+
override fun getIndexer(): DataIndexer<String, String, FileContent> {
25+
return DataIndexer { fileContent ->
26+
val phpFile = fileContent.psiFile as? PhpFile ?: return@DataIndexer emptyMap()
27+
val result = mutableMapOf<String, String>()
28+
val classes = PsiTreeUtil.findChildrenOfType(phpFile, PhpClass::class.java)
29+
for (phpClass in classes) {
30+
if (phpClass.hasAttribute(TemporalClasses.WORKFLOW)) {
31+
val fqn = phpClass.fqn
32+
result[fqn] = fqn
33+
}
34+
}
35+
result
36+
}
37+
}
38+
39+
override fun getInputFilter(): FileBasedIndex.InputFilter {
40+
return FileBasedIndex.InputFilter { file -> file.fileType == PhpFileType.INSTANCE }
41+
}
42+
43+
override fun getValueExternalizer(): DataExternalizer<String> = EnumeratorStringDescriptor.INSTANCE
44+
}

0 commit comments

Comments
 (0)