Skip to content

Commit 5953d61

Browse files
committed
feat: add toolchain command support and dependencies function provider #308
1 parent d0f8970 commit 5953d61

File tree

8 files changed

+143
-12
lines changed

8 files changed

+143
-12
lines changed

build.gradle.kts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ project(":") {
261261
pluginModule(implementation(project(":exts:ext-terminal")))
262262
pluginModule(implementation(project(":exts:ext-mermaid")))
263263
pluginModule(implementation(project(":exts:ext-vue")))
264+
pluginModule(implementation(project(":exts:ext-dependencies")))
264265
pluginModule(implementation(project(":exts:ext-endpoints")))
265266
pluginModule(implementation(project(":exts:ext-plantuml")))
266267
pluginModule(implementation(project(":exts:devins-lang")))
@@ -284,6 +285,7 @@ project(":") {
284285
implementation(project(":exts:ext-terminal"))
285286
implementation(project(":exts:ext-mermaid"))
286287
implementation(project(":exts:ext-vue"))
288+
implementation(project(":exts:ext-dependencies"))
287289
implementation(project(":exts:ext-plantuml"))
288290
implementation(project(":exts:ext-endpoints"))
289291
implementation(project(":exts:devins-lang"))
@@ -613,6 +615,17 @@ project(":exts:ext-vue") {
613615
implementation(project(":core"))
614616
}
615617
}
618+
project(":exts:ext-dependencies") {
619+
dependencies {
620+
intellijPlatform {
621+
intellijIde(prop("ideaVersion"))
622+
intellijPlugins(ideaPlugins)
623+
bundledPlugin("org.jetbrains.security.package-checker")
624+
}
625+
626+
implementation(project(":core"))
627+
}
628+
}
616629

617630
project(":exts:ext-plantuml") {
618631
dependencies {

core/src/main/kotlin/cc/unitmesh/devti/devin/dataprovider/BuiltinCommand.kt

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cc.unitmesh.devti.devin.dataprovider
22

33
import cc.unitmesh.devti.AutoDevIcons
4+
import cc.unitmesh.devti.provider.toolchain.ToolchainFunctionProvider
45
import com.intellij.icons.AllIcons
56
import java.nio.charset.StandardCharsets
67
import javax.swing.Icon
@@ -107,6 +108,14 @@ enum class BuiltinCommand(
107108
),
108109
OPEN("open", "Open a file in the editor", AllIcons.Actions.MenuOpen, false, true),
109110
RIPGREP_SEARCH("ripgrepSearch", "Search text in the project with ripgrep", AllIcons.Actions.Regex, false, true),
111+
TOOLCHAIN_COMMAND(
112+
"x",
113+
"Execute custom toolchain command",
114+
AllIcons.Actions.Execute,
115+
true,
116+
false,
117+
enableInSketch = false
118+
),
110119
;
111120

112121
companion object {
@@ -124,8 +133,28 @@ enum class BuiltinCommand(
124133
}
125134
}
126135

127-
fun fromString(agentName: String): BuiltinCommand? = values().find { it.commandName == agentName }
136+
fun fromString(commandName: String): BuiltinCommand? {
137+
val builtinCommand = entries.find { it.commandName == commandName }
138+
if (builtinCommand == null) {
139+
val providerName = toolchainProviderName(commandName)
140+
val provider = ToolchainFunctionProvider.lookup(providerName)
141+
if (provider != null) {
142+
return TOOLCHAIN_COMMAND
143+
}
144+
145+
return null
146+
}
147+
148+
return builtinCommand
149+
}
150+
151+
fun toolchainProviderName(commandName: String): String {
152+
val commandProviderName = commandName.substring(0, 1).uppercase() + commandName.substring(1)
153+
val providerName = commandProviderName + "FunctionProvider"
154+
return providerName
155+
}
128156

129-
val READ_COMMANDS = setOf(DIR, LOCAL_SEARCH, FILE, REV, STRUCTURE, SYMBOL, DATABASE, RELATED, RIPGREP_SEARCH, BROWSE)
157+
val READ_COMMANDS =
158+
setOf(DIR, LOCAL_SEARCH, FILE, REV, STRUCTURE, SYMBOL, DATABASE, RELATED, RIPGREP_SEARCH, BROWSE)
130159
}
131160
}

core/src/main/kotlin/cc/unitmesh/devti/devin/dataprovider/CustomCommand.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package cc.unitmesh.devti.devin.dataprovider
22

3-
import cc.unitmesh.devti.custom.team.TeamPromptsBuilder
43
import cc.unitmesh.devti.AutoDevIcons
4+
import cc.unitmesh.devti.custom.team.TeamPromptsBuilder
55
import com.intellij.openapi.project.Project
66
import com.intellij.openapi.vfs.VirtualFile
77
import javax.swing.Icon
@@ -26,8 +26,8 @@ data class CustomCommand(
2626
return CustomCommand(file.nameWithoutExtension, content)
2727
}
2828

29-
fun fromString(project: Project, agentName: String): CustomCommand? {
30-
return all(project).find { it.commandName == agentName }
29+
fun fromString(project: Project, commandName: String): CustomCommand? {
30+
return all(project).find { it.commandName == commandName }
3131
}
3232
}
3333
}

exts/devins-lang/src/main/kotlin/cc/unitmesh/devti/language/compiler/DevInsCompiler.kt

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,20 @@ import cc.unitmesh.devti.devin.InsCommand
66
import cc.unitmesh.devti.language.compiler.error.DEVINS_ERROR
77
import cc.unitmesh.devti.language.compiler.exec.*
88
import cc.unitmesh.devti.devin.dataprovider.BuiltinCommand
9+
import cc.unitmesh.devti.devin.dataprovider.BuiltinCommand.Companion.toolchainProviderName
910
import cc.unitmesh.devti.devin.dataprovider.CustomCommand
1011
import cc.unitmesh.devti.devin.dataprovider.ToolHubVariable
1112
import cc.unitmesh.devti.language.parser.CodeBlockElement
1213
import cc.unitmesh.devti.language.psi.DevInFile
1314
import cc.unitmesh.devti.language.psi.DevInTypes
1415
import cc.unitmesh.devti.language.psi.DevInUsed
16+
import cc.unitmesh.devti.provider.toolchain.ToolchainFunctionProvider
17+
import cc.unitmesh.devti.util.parser.CodeFence
1518
import com.intellij.openapi.diagnostic.logger
1619
import com.intellij.openapi.editor.Editor
1720
import com.intellij.openapi.project.Project
1821
import com.intellij.openapi.project.guessProjectDir
22+
import com.intellij.openapi.util.NlsSafe
1923
import com.intellij.psi.PsiElement
2024
import com.intellij.psi.util.elementType
2125
import kotlinx.coroutines.runBlocking
@@ -86,9 +90,10 @@ class DevInsCompiler(
8690

8791
when (firstChild.elementType) {
8892
DevInTypes.COMMAND_START -> {
89-
val command = BuiltinCommand.fromString(id?.text ?: "")
93+
val originCmdName = id?.text ?: ""
94+
val command = BuiltinCommand.fromString(originCmdName)
9095
if (command == null) {
91-
CustomCommand.fromString(myProject, id?.text ?: "")?.let { cmd ->
96+
CustomCommand.fromString(myProject, originCmdName)?.let { cmd ->
9297
DevInFile.fromString(myProject, cmd.content).let { file ->
9398
DevInsCompiler(myProject, file).compile().let {
9499
output.append(it.output)
@@ -99,15 +104,14 @@ class DevInsCompiler(
99104
return
100105
}
101106

102-
103107
output.append(used.text)
104-
logger.warn("Unknown command: ${id?.text}")
108+
logger.warn("Unknown command: $originCmdName")
105109
result.hasError = true
106110
return
107111
}
108112

109113
if (!command.requireProps) {
110-
processingCommand(command, "", used, fallbackText = used.text)
114+
processingCommand(command, "", used, fallbackText = used.text, originCmdName)
111115
return
112116
}
113117

@@ -120,7 +124,7 @@ class DevInsCompiler(
120124
return
121125
}
122126

123-
processingCommand(command, propElement!!.text, used, fallbackText = used.text)
127+
processingCommand(command, propElement!!.text, used, fallbackText = used.text, originCmdName)
124128
}
125129

126130
DevInTypes.AGENT_START -> {
@@ -161,7 +165,13 @@ class DevInsCompiler(
161165
}
162166
}
163167

164-
private fun processingCommand(commandNode: BuiltinCommand, prop: String, used: DevInUsed, fallbackText: String) {
168+
private fun processingCommand(
169+
commandNode: BuiltinCommand,
170+
prop: String,
171+
used: DevInUsed,
172+
fallbackText: String,
173+
originCmdName: @NlsSafe String
174+
) {
165175
val command: InsCommand = when (commandNode) {
166176
BuiltinCommand.FILE -> {
167177
FileInsCommand(myProject, prop)
@@ -271,6 +281,21 @@ class DevInsCompiler(
271281
OpenInsCommand(myProject, prop)
272282
}
273283

284+
BuiltinCommand.TOOLCHAIN_COMMAND -> {
285+
result.isLocalCommand = true
286+
try {
287+
val providerName = toolchainProviderName(originCmdName)
288+
val provider = ToolchainFunctionProvider.lookup(providerName)
289+
if (provider != null) {
290+
executeExtensionFunction(used, prop, provider)
291+
} else {
292+
PrintInsCommand("/" + commandNode.commandName + ":" + prop)
293+
}
294+
} catch (e: Exception) {
295+
PrintInsCommand("/" + commandNode.commandName + ":" + prop)
296+
}
297+
}
298+
274299
else -> {
275300
PrintInsCommand("/" + commandNode.commandName + ":" + prop)
276301
}
@@ -300,6 +325,23 @@ class DevInsCompiler(
300325
output.append(result)
301326
}
302327

328+
private fun executeExtensionFunction(
329+
used: DevInUsed,
330+
prop: String,
331+
provider: ToolchainFunctionProvider
332+
): PrintInsCommand {
333+
val codeContent: String? = lookupNextCode(used)?.text
334+
val args = if (codeContent != null) {
335+
val code = CodeFence.parse(codeContent).text
336+
listOf(code)
337+
} else {
338+
listOf()
339+
}
340+
341+
val result = provider.execute(myProject, prop, args, emptyMap())
342+
return PrintInsCommand(result.toString())
343+
}
344+
303345
private fun lookupNextCode(used: DevInUsed): CodeBlockElement? {
304346
val devInCode: CodeBlockElement?
305347
var next: PsiElement? = used
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package cc.unitmesh.dependencies
2+
3+
import cc.unitmesh.devti.provider.toolchain.ToolchainFunctionProvider
4+
import com.intellij.openapi.module.ModuleManager
5+
import com.intellij.openapi.project.Project
6+
import com.intellij.packageChecker.api.BuildFileProvider
7+
import com.intellij.packageChecker.api.PackageDeclaration
8+
import com.intellij.packageChecker.model.ProjectDependenciesModel
9+
10+
class DependenciesFunctionProvider : ToolchainFunctionProvider {
11+
override fun isApplicable(project: Project, funcName: String): Boolean {
12+
return funcName == "dependencies"
13+
}
14+
15+
fun listDeps(project: Project): List<PackageDeclaration> {
16+
val modules = ModuleManager.getInstance(project).modules
17+
val flatten = ProjectDependenciesModel.supportedModels(project).map {
18+
modules.map { module ->
19+
it.declaredDependencies(module)
20+
}.flatten()
21+
}.flatten()
22+
23+
// BuildFileProvider.EP_NAME
24+
return flatten
25+
}
26+
27+
override fun execute(
28+
project: Project,
29+
funcName: String,
30+
args: List<Any>,
31+
allVariables: Map<String, Any?>
32+
): Any {
33+
return listDeps(project)
34+
}
35+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<idea-plugin package="cc.unitmesh.dependencies">
2+
<!--suppress PluginXmlValidity -->
3+
<dependencies>
4+
<plugin id="org.jetbrains.security.package-checker"/>
5+
</dependencies>
6+
7+
<extensions defaultExtensionNs="cc.unitmesh">
8+
<toolchainFunctionProvider implementation="cc.unitmesh.dependencies.DependenciesFunctionProvider"/>
9+
</extensions>
10+
</idea-plugin>

settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ include(
2626
"exts:ext-mermaid",
2727
"exts:ext-endpoints",
2828
"exts:ext-vue",
29+
"exts:ext-dependencies",
2930

3031
// the Input Language support for AutoDev
3132
"exts:devins-lang"

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,6 @@
4141
<module name="cc.unitmesh.httpclient"/>
4242
<module name="cc.unitmesh.endpoints"/>
4343
<module name="cc.unitmesh.vue"/>
44+
<module name="cc.unitmesh.dependencies"/>
4445
</content>
4546
</idea-plugin>

0 commit comments

Comments
 (0)