Skip to content

Commit 1262136

Browse files
committed
feat(parser): add support for THOUGHT and PLAN tags #331
- Introduce new XML tag parsing for THOUG
1 parent 1e4d41c commit 1262136

File tree

5 files changed

+232
-0
lines changed

5 files changed

+232
-0
lines changed

core/src/223/main/resources/META-INF/autodev-core.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@
266266
<langSketchProvider implementation="cc.unitmesh.devti.sketch.ui.webview.WebpageSketchProvider"/>
267267
<langSketchProvider implementation="cc.unitmesh.devti.sketch.ui.openapi.OpenAPISketchProvider"/>
268268
<langSketchProvider implementation="cc.unitmesh.devti.sketch.ui.MarkdownPreviewSketchProvider"/>
269+
<langSketchProvider implementation="cc.unitmesh.devti.sketch.ui.ThoughtPlanSketchProvider"/>
269270

270271
<toolchainFunctionProvider implementation="cc.unitmesh.devti.bridge.archview.ComponentViewFunctionProvider"/>
271272
<toolchainFunctionProvider implementation="cc.unitmesh.devti.bridge.archview.ContainerViewFunctionProvider"/>

core/src/233/main/resources/META-INF/autodev-core.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@
268268
<langSketchProvider implementation="cc.unitmesh.devti.sketch.ui.webview.WebpageSketchProvider"/>
269269
<langSketchProvider implementation="cc.unitmesh.devti.sketch.ui.openapi.OpenAPISketchProvider"/>
270270
<langSketchProvider implementation="cc.unitmesh.devti.sketch.ui.MarkdownPreviewSketchProvider"/>
271+
<langSketchProvider implementation="cc.unitmesh.devti.sketch.ui.ThoughtPlanSketchProvider"/>
271272

272273
<toolchainFunctionProvider implementation="cc.unitmesh.devti.bridge.archview.ComponentViewFunctionProvider"/>
273274
<toolchainFunctionProvider implementation="cc.unitmesh.devti.bridge.archview.ContainerViewFunctionProvider"/>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package cc.unitmesh.devti.sketch.ui
2+
3+
import cc.unitmesh.devti.sketch.ui.code.CodeHighlightSketch
4+
import com.intellij.openapi.project.Project
5+
6+
class ThoughtPlanSketchProvider : LanguageSketchProvider {
7+
override fun isSupported(lang: String): Boolean = lang == "plan"
8+
9+
override fun create(project: Project, content: String): ExtensionLangSketch {
10+
return object : CodeHighlightSketch(project, content, null), ExtensionLangSketch {
11+
override fun getExtensionName(): String = "ThoughtPlan"
12+
}
13+
}
14+
}

core/src/main/kotlin/cc/unitmesh/devti/util/parser/CodeFence.kt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ class CodeFence(
1414
private var lastTxtBlock: CodeFence? = null
1515
val devinStartRegex = Regex("<devin>")
1616
val devinEndRegex = Regex("</devin>")
17+
val thoughtStartRegex = Regex("<THOUGHT>")
18+
val thoughtEndRegex = Regex("</THOUGHT>")
19+
val planStartRegex = Regex("<PLAN>")
20+
val planEndRegex = Regex("</PLAN>")
1721

1822
fun parse(content: String): CodeFence {
1923
val languageRegex = Regex("\\s*```([\\w#+ ]*)")
@@ -82,6 +86,8 @@ class CodeFence(
8286
if (content.contains("```devin\n")) {
8387
content = preProcessDevinBlock(content)
8488
}
89+
90+
content = preProcessXmlBlocks(content)
8591

8692
val startMatches = devinStartRegex.findAll(content)
8793
for (startMatch in startMatches) {
@@ -117,6 +123,38 @@ class CodeFence(
117123

118124
return codeFences.filter { it.text.isNotEmpty() }
119125
}
126+
127+
private fun preProcessXmlBlocks(content: String): String {
128+
var currentContent = content
129+
130+
// 处理<THOUGHT>标签
131+
val thoughtMatches = Regex("(?<=^|\\n)<THOUGHT>([\\s\\S]*?)</THOUGHT>\\n?").findAll(content).toList()
132+
for (match in thoughtMatches) {
133+
val thoughtContent = match.groups[1]?.value ?: ""
134+
// 检查是否有内部的<PLAN>标签
135+
val planMatch = Regex("<PLAN>([\\s\\S]*?)</PLAN>").find(thoughtContent)
136+
137+
if (planMatch != null) {
138+
val planContent = planMatch.groups[1]?.value?.trim() ?: ""
139+
// 将<PLAN>内容替换为Markdown代码块格式
140+
val processedContent = thoughtContent.replace(planMatch.value, "\n```plan\n$planContent\n```\n")
141+
currentContent = currentContent.replace(match.value, processedContent)
142+
} else {
143+
// 如果没有内部PLAN标签,保持原样
144+
currentContent = currentContent
145+
}
146+
}
147+
148+
// 直接处理独立的<PLAN>标签
149+
val planMatches = Regex("(?<=^|\\n)<PLAN>([\\s\\S]*?)</PLAN>\\n?").findAll(currentContent).toList()
150+
for (match in planMatches) {
151+
val planContent = match.groups[1]?.value?.trim() ?: ""
152+
val replacement = "\n```plan\n$planContent\n```\n"
153+
currentContent = currentContent.replace(match.value, replacement)
154+
}
155+
156+
return currentContent
157+
}
120158

121159
val devinRegexBlock = Regex("(?<=^|\\n)```devin\\n([\\s\\S]*?)\\n```\\n")
122160
val normalCodeBlock = Regex("\\s*```([\\w#+ ]*)\\n")
@@ -233,6 +271,8 @@ class CodeFence(
233271
"sh" -> "Shell Script"
234272
"bash" -> "Shell Script"
235273
"http" -> "HTTP Request"
274+
"plan" -> "Plain Text"
275+
"thought" -> "Plain Text"
236276
else -> languageName
237277
}
238278

@@ -278,6 +318,8 @@ class CodeFence(
278318
"shell script" -> "sh"
279319
"bash" -> "sh"
280320
"devin" -> "devin"
321+
"plan" -> "plan"
322+
"thought" -> "thought"
281323
else -> languageId
282324
}
283325
}
@@ -307,6 +349,8 @@ class CodeFence(
307349
"scala" -> "Scala"
308350
"rs" -> "Rust"
309351
"http" -> "HTTP Request"
352+
"plan" -> "PLAN"
353+
"thought" -> "THOUGHT"
310354
else -> extension
311355
}
312356
}

core/src/test/kotlin/cc/unitmesh/devti/parser/CodeFenceTest.kt

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,4 +556,176 @@ Index: src/main/java/cc/unitmesh/untitled/demo/repository/BlogRepository.java
556556
val codeFences = CodeFence.parseAll(content)
557557
assertEquals(codeFences.size, 1)
558558
}
559+
560+
fun testShouldParsePlanTag() {
561+
val content = """
562+
<PLAN>
563+
1. 领域模型重构:
564+
- 将BlogPost实体合并到Blog聚合根,建立完整的领域对象
565+
- 添加领域行为方法(发布、审核、评论等)
566+
- 引入值对象(BlogId、Content等)
567+
</PLAN>
568+
""".trimIndent()
569+
570+
val code = CodeFence.parse(content)
571+
assertEquals(
572+
code.text,
573+
"""
574+
1. 领域模型重构:
575+
- 将BlogPost实体合并到Blog聚合根,建立完整的领域对象
576+
- 添加领域行为方法(发布、审核、评论等)
577+
- 引入值对象(BlogId、Content等)
578+
""".trimIndent()
579+
)
580+
assertTrue(code.isComplete)
581+
assertEquals("plan", code.extension)
582+
assertEquals("plan", code.originLanguage)
583+
}
584+
585+
fun testShouldParseThoughtTag() {
586+
val content = """
587+
<THOUGHT>
588+
我需要实现博客系统的领域模型重构,主要包括以下步骤:
589+
1. 将BlogPost合并到Blog聚合根
590+
2. 添加领域行为
591+
</THOUGHT>
592+
""".trimIndent()
593+
594+
val code = CodeFence.parse(content)
595+
assertEquals(
596+
code.text,
597+
"""
598+
我需要实现博客系统的领域模型重构,主要包括以下步骤:
599+
1. 将BlogPost合并到Blog聚合根
600+
2. 添加领域行为
601+
""".trimIndent()
602+
)
603+
assertTrue(code.isComplete)
604+
assertEquals("thought", code.extension)
605+
assertEquals("thought", code.originLanguage)
606+
}
607+
608+
fun testShouldParseNestedPlanInThought() {
609+
val content = """
610+
<THOUGHT>
611+
我需要对系统进行重构,首先列出计划:
612+
613+
<PLAN>
614+
1. 领域模型重构:
615+
- 将BlogPost实体合并到Blog聚合根,建立完整的领域对象
616+
- 添加领域行为方法(发布、审核、评论等)
617+
618+
2. 分层结构调整:
619+
- 清理entity层冗余对象,建立清晰的domain层
620+
- 实现领域服务与基础设施层分离
621+
</PLAN>
622+
623+
然后按照计划实施重构。
624+
</THOUGHT>
625+
""".trimIndent()
626+
627+
val code = CodeFence.parse(content)
628+
assertEquals(
629+
code.text,
630+
"""
631+
1. 领域模型重构:
632+
- 将BlogPost实体合并到Blog聚合根,建立完整的领域对象
633+
- 添加领域行为方法(发布、审核、评论等)
634+
635+
2. 分层结构调整:
636+
- 清理entity层冗余对象,建立清晰的domain层
637+
- 实现领域服务与基础设施层分离
638+
""".trimIndent()
639+
)
640+
assertTrue(code.isComplete)
641+
assertEquals("plan", code.extension)
642+
assertEquals("plan", code.originLanguage)
643+
}
644+
645+
fun testShouldParseAllWithXmlTags() {
646+
val content = """
647+
首先,我需要思考重构的步骤:
648+
649+
<THOUGHT>
650+
系统重构需要考虑领域驱动设计原则,确保聚合根的完整性。
651+
652+
<PLAN>
653+
1. 领域模型重构:
654+
- 将BlogPost实体合并到Blog聚合根,建立完整的领域对象
655+
- 添加领域行为方法(发布、审核、评论等)
656+
657+
2. 分层结构调整:
658+
- 清理entity层冗余对象
659+
</PLAN>
660+
661+
这样的重构可以提高系统的内聚性。
662+
</THOUGHT>
663+
664+
然后,我们可以开始代码实现:
665+
666+
```java
667+
public class Blog {
668+
private BlogId id;
669+
private String title;
670+
private String content;
671+
672+
public void publish() {
673+
// 实现发布逻辑
674+
}
675+
}
676+
```
677+
678+
<devin>
679+
/patch
680+
```patch
681+
Index: src/main/java/cc/unitmesh/untitled/demo/repository/BlogRepository.java
682+
--- src/main/java/cc/unitmesh/untitled/demo/repository/BlogRepository.java (revision 1)
683+
+++ src/main/java/cc/unitmesh/untitled/demo/repository/BlogRepository.java (revision 2)
684+
```
685+
</devin>
686+
687+
<PLAN>
688+
3. 战术模式实现:
689+
- 使用工厂模式处理复杂对象创建
690+
- 实现仓储接口与领域层的依赖倒置
691+
</PLAN>
692+
""".trimIndent()
693+
694+
val codeFences = CodeFence.parseAll(content)
695+
assertEquals(6, codeFences.size)
696+
697+
// 检查第一个代码段是Markdown内容
698+
assertEquals("首先,我需要思考重构的步骤:\n" +
699+
"\n" +
700+
"\n" +
701+
"系统重构需要考虑领域驱动设计原则,确保聚合根的完整性。", codeFences[0].text)
702+
703+
// 检查第二个代码段是plan内容(嵌套在THOUGHT中的PLAN)
704+
assertEquals(
705+
"""
706+
1. 领域模型重构:
707+
- 将BlogPost实体合并到Blog聚合根,建立完整的领域对象
708+
- 添加领域行为方法(发布、审核、评论等)
709+
710+
2. 分层结构调整:
711+
- 清理entity层冗余对象
712+
""".trimIndent(),
713+
codeFences[1].text
714+
)
715+
assertEquals("plan", codeFences[1].extension)
716+
717+
// 检查第三个代码段是Java代码
718+
assertEquals("这样的重构可以提高系统的内聚性。\n\n然后,我们可以开始代码实现:", codeFences[2].text)
719+
720+
// 检查第四个代码段是单独的PLAN标签内容
721+
assertEquals(
722+
"""
723+
3. 战术模式实现:
724+
- 使用工厂模式处理复杂对象创建
725+
- 实现仓储接口与领域层的依赖倒置
726+
""".trimIndent(),
727+
codeFences[3].text
728+
)
729+
assertEquals("plan", codeFences[3].extension)
730+
}
559731
}

0 commit comments

Comments
 (0)