Skip to content

Commit b5173f3

Browse files
nam-hleclaude
andauthored
030 Search everywhere tasks: Add nadle tasks to Search Everywhere dialog (#46)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent dffc22d commit b5173f3

File tree

5 files changed

+177
-6
lines changed

5 files changed

+177
-6
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.github.nadlejs.intellij.plugin.run
2+
3+
import java.nio.file.Path
4+
5+
data class NadleTask(
6+
val name: String,
7+
val configFilePath: Path,
8+
val workingDirectory: Path
9+
)

src/main/kotlin/com/github/nadlejs/intellij/plugin/run/NadleTaskScanner.kt

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ object NadleTaskScanner {
1818

1919
private val CONFIG_PATTERN = Regex("""^nadle\.config\.[cm]?[jt]s$""")
2020

21-
fun scanTasks(rootDir: Path): List<String> {
21+
fun scanTasks(rootDir: Path): List<String> =
22+
scanTasksDetailed(rootDir).map { it.name }.sorted()
23+
24+
fun scanTasksDetailed(rootDir: Path): List<NadleTask> {
2225
if (!Files.isDirectory(rootDir)) return emptyList()
2326

24-
val tasks = mutableListOf<String>()
27+
val tasks = mutableListOf<NadleTask>()
2528

2629
Files.walkFileTree(rootDir, object : SimpleFileVisitor<Path>() {
2730
override fun preVisitDirectory(
@@ -49,13 +52,20 @@ object NadleTaskScanner {
4952
val relDir = rootDir.relativize(file.parent)
5053

5154
for (name in names) {
52-
if (relDir.toString().isEmpty()) {
53-
tasks.add(name)
55+
val qualifiedName = if (relDir.toString().isEmpty()) {
56+
name
5457
} else {
5558
val prefix = relDir.toString()
5659
.replace(File.separatorChar, ':')
57-
tasks.add(":$prefix:$name")
60+
":$prefix:$name"
5861
}
62+
tasks.add(
63+
NadleTask(
64+
name = qualifiedName,
65+
configFilePath = file.toAbsolutePath(),
66+
workingDirectory = file.parent.toAbsolutePath()
67+
)
68+
)
5969
}
6070
}
6171
return FileVisitResult.CONTINUE
@@ -67,6 +77,6 @@ object NadleTaskScanner {
6777
): FileVisitResult = FileVisitResult.CONTINUE
6878
})
6979

70-
return tasks.sorted()
80+
return tasks
7181
}
7282
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package com.github.nadlejs.intellij.plugin.search
2+
3+
import com.github.nadlejs.intellij.plugin.run.NadleTask
4+
import com.github.nadlejs.intellij.plugin.run.NadleTaskConfigurationType
5+
import com.github.nadlejs.intellij.plugin.run.NadleTaskRunConfiguration
6+
import com.github.nadlejs.intellij.plugin.run.NadleTaskScanner
7+
import com.github.nadlejs.intellij.plugin.util.NadleIcons
8+
import com.intellij.execution.runners.ExecutionUtil
9+
import com.intellij.execution.RunManager
10+
import com.intellij.execution.configurations.ConfigurationTypeUtil
11+
import com.intellij.execution.executors.DefaultRunExecutor
12+
import com.intellij.ide.actions.searcheverywhere.FoundItemDescriptor
13+
import com.intellij.ide.actions.searcheverywhere.WeightedSearchEverywhereContributor
14+
import com.intellij.openapi.actionSystem.AnActionEvent
15+
import com.intellij.openapi.progress.ProgressIndicator
16+
import com.intellij.openapi.project.Project
17+
import com.intellij.psi.codeStyle.MinusculeMatcher
18+
import com.intellij.psi.codeStyle.NameUtil
19+
import com.intellij.util.Processor
20+
import java.awt.Component
21+
import java.nio.file.Path
22+
import javax.swing.DefaultListCellRenderer
23+
import javax.swing.JList
24+
import javax.swing.ListCellRenderer
25+
26+
class NadleTaskSearchEverywhereContributor(
27+
private val project: Project
28+
) : WeightedSearchEverywhereContributor<NadleTask> {
29+
30+
override fun getSearchProviderId(): String = javaClass.name
31+
32+
override fun getGroupName(): String = "Nadle Tasks"
33+
34+
override fun getSortWeight(): Int = 300
35+
36+
override fun showInFindResults(): Boolean = false
37+
38+
override fun isEmptyPatternSupported(): Boolean = true
39+
40+
override fun getElementsRenderer(): ListCellRenderer<in NadleTask> {
41+
return object : DefaultListCellRenderer() {
42+
override fun getListCellRendererComponent(
43+
list: JList<*>?,
44+
value: Any?,
45+
index: Int,
46+
isSelected: Boolean,
47+
cellHasFocus: Boolean
48+
): Component {
49+
val component = super.getListCellRendererComponent(
50+
list, value, index, isSelected, cellHasFocus
51+
)
52+
if (value is NadleTask) {
53+
text = value.name
54+
icon = NadleIcons.Nadle
55+
}
56+
return component
57+
}
58+
}
59+
}
60+
61+
override fun getDataForItem(element: NadleTask, dataId: String): Any? = null
62+
63+
override fun fetchWeightedElements(
64+
pattern: String,
65+
progressIndicator: ProgressIndicator,
66+
consumer: Processor<in FoundItemDescriptor<NadleTask>>
67+
) {
68+
val basePath = project.basePath ?: return
69+
val tasks = NadleTaskScanner.scanTasksDetailed(Path.of(basePath))
70+
71+
val matcher = if (pattern.isNotEmpty()) {
72+
NameUtil.buildMatcher("*$pattern").build()
73+
} else {
74+
null
75+
}
76+
77+
for (task in tasks) {
78+
progressIndicator.checkCanceled()
79+
if (matcher == null || matcher.matches(task.name)) {
80+
val weight = matcher?.matchingDegree(task.name) ?: 0
81+
consumer.process(FoundItemDescriptor(task, weight))
82+
}
83+
}
84+
}
85+
86+
override fun processSelectedItem(
87+
selected: NadleTask,
88+
modifiers: Int,
89+
searchText: String
90+
): Boolean {
91+
val runManager = RunManager.getInstance(project)
92+
val configType = ConfigurationTypeUtil.findConfigurationType(
93+
NadleTaskConfigurationType::class.java
94+
)
95+
val factory = configType.configurationFactories[0]
96+
97+
val existing = runManager.allSettings.find { settings ->
98+
val config = settings.configuration
99+
config is NadleTaskRunConfiguration
100+
&& config.taskName == selected.name
101+
&& config.configFilePath == selected.configFilePath.toString()
102+
}
103+
104+
val settings = existing ?: runManager.createConfiguration(
105+
selected.name,
106+
factory
107+
).also { settings ->
108+
val config = settings.configuration as NadleTaskRunConfiguration
109+
config.taskName = selected.name
110+
config.configFilePath = selected.configFilePath.toString()
111+
config.workingDirectory = selected.workingDirectory.toString()
112+
settings.isTemporary = true
113+
runManager.addConfiguration(settings)
114+
}
115+
116+
runManager.selectedConfiguration = settings
117+
ExecutionUtil.runConfiguration(settings, DefaultRunExecutor.getRunExecutorInstance())
118+
return true
119+
}
120+
121+
override fun fetchElements(
122+
pattern: String,
123+
progressIndicator: ProgressIndicator,
124+
consumer: Processor<in NadleTask>
125+
) {
126+
fetchWeightedElements(pattern, progressIndicator) { descriptor ->
127+
consumer.process(descriptor.item)
128+
}
129+
}
130+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.github.nadlejs.intellij.plugin.search
2+
3+
import com.intellij.ide.actions.searcheverywhere.SearchEverywhereContributor
4+
import com.intellij.ide.actions.searcheverywhere.SearchEverywhereContributorFactory
5+
import com.intellij.openapi.actionSystem.AnActionEvent
6+
7+
class NadleTaskSearchEverywhereContributorFactory
8+
: SearchEverywhereContributorFactory<Any> {
9+
10+
override fun createContributor(
11+
initEvent: AnActionEvent
12+
): SearchEverywhereContributor<Any> {
13+
val project = initEvent.project
14+
?: throw IllegalStateException("Project is required")
15+
@Suppress("UNCHECKED_CAST")
16+
return NadleTaskSearchEverywhereContributor(project)
17+
as SearchEverywhereContributor<Any>
18+
}
19+
}

src/main/resources/META-INF/plugin.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,8 @@
4444
<lang.psiStructureViewFactory language="TypeScript"
4545
order="first"
4646
implementationClass="com.github.nadlejs.intellij.plugin.structure.NadleStructureViewFactory"/>
47+
48+
<searchEverywhereContributor
49+
implementation="com.github.nadlejs.intellij.plugin.search.NadleTaskSearchEverywhereContributorFactory"/>
4750
</extensions>
4851
</idea-plugin>

0 commit comments

Comments
 (0)