From 19a0e97a1aba87af61bbae27f8ff478440a242b6 Mon Sep 17 00:00:00 2001 From: Phodal Huang Date: Wed, 6 Mar 2024 10:58:03 +0800 Subject: [PATCH] fix(gui): improve code block rendering and parsing #51 The commit addresses several issues related to code block rendering and parsing in the GUI. It fixes a bug where the foreground color of code blocks was not being set correctly and ensures that the code block component is added to the center panel. Additionally, the commit enhances the code parsing utility to correctly handle empty code blocks within markdown content, treating them as markdown instead of code. --- .../devti/gui/chat/AutoDevInputSection.kt | 2 ++ .../cc/unitmesh/devti/gui/chat/MessageView.kt | 6 ++++-- .../cc/unitmesh/devti/util/parser/CodeUtil.kt | 9 ++++++++- .../temporary/gui/block/CodeBlockView.kt | 6 +++--- .../temporary/gui/block/MessageBlock.kt | 2 +- .../cc/unitmesh/devti/parser/CodeUtilTest.kt | 19 +++++++++++++++---- 6 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/main/kotlin/cc/unitmesh/devti/gui/chat/AutoDevInputSection.kt b/src/main/kotlin/cc/unitmesh/devti/gui/chat/AutoDevInputSection.kt index c36fac653d..0400f5e185 100644 --- a/src/main/kotlin/cc/unitmesh/devti/gui/chat/AutoDevInputSection.kt +++ b/src/main/kotlin/cc/unitmesh/devti/gui/chat/AutoDevInputSection.kt @@ -4,6 +4,7 @@ import cc.unitmesh.devti.AutoDevBundle import cc.unitmesh.devti.AutoDevIcons import cc.unitmesh.devti.counit.configurable.customAgentSetting import cc.unitmesh.devti.counit.model.CustomAgentConfig +import cc.unitmesh.devti.counit.model.CustomAgentState import cc.unitmesh.devti.llms.tokenizer.Tokenizer import cc.unitmesh.devti.llms.tokenizer.TokenizerImpl import cc.unitmesh.devti.settings.AutoDevSettingsState @@ -222,6 +223,7 @@ class AutoDevInputSection(private val project: Project, val disposable: Disposab } fun resetAgent() { + (customRag.selectedItem as CustomAgentConfig).state = CustomAgentState.START customRag.selectedItem = defaultRag } diff --git a/src/main/kotlin/cc/unitmesh/devti/gui/chat/MessageView.kt b/src/main/kotlin/cc/unitmesh/devti/gui/chat/MessageView.kt index d8c868dff3..8e9ce0d1c1 100644 --- a/src/main/kotlin/cc/unitmesh/devti/gui/chat/MessageView.kt +++ b/src/main/kotlin/cc/unitmesh/devti/gui/chat/MessageView.kt @@ -98,8 +98,10 @@ class MessageView(private val message: String, val role: ChatRole, private val d } blockView.initialize() - blockView.getComponent()?.setForeground(JBUI.CurrentTheme.Label.foreground()) - blockView.getComponent()?.let { component -> centerPanel.add(component) } + val component = blockView.getComponent() ?: return@forEach + + component.setForeground(JBUI.CurrentTheme.Label.foreground()) + centerPanel.add(component) } } diff --git a/src/main/kotlin/cc/unitmesh/devti/util/parser/CodeUtil.kt b/src/main/kotlin/cc/unitmesh/devti/util/parser/CodeUtil.kt index e7f593f3d6..0bea2f0795 100644 --- a/src/main/kotlin/cc/unitmesh/devti/util/parser/CodeUtil.kt +++ b/src/main/kotlin/cc/unitmesh/devti/util/parser/CodeUtil.kt @@ -6,7 +6,8 @@ class Code(val language: Language, val text: String, val isComplete: Boolean) { companion object { fun parse(content: String): Code { val regex = Regex("```([\\w#+]*)") - val lines = content.lines() + // convert content \\n to \n + val lines = content.replace("\\n", "\n").lines() var codeStarted = false var codeClosed = false @@ -48,6 +49,12 @@ class Code(val language: Language, val text: String, val isComplete: Boolean) { val trimmedCode = codeBuilder.substring(startIndex, endIndex + 1).toString() val language = findLanguage(languageId ?: "") + + // if content is not empty, but code is empty, then it's a markdown + if (trimmedCode.isEmpty()) { + return Code(findLanguage("markdown"), content.replace("\\n", "\n"), codeClosed) + } + return Code(language, trimmedCode, codeClosed) } diff --git a/src/main/kotlin/com/intellij/temporary/gui/block/CodeBlockView.kt b/src/main/kotlin/com/intellij/temporary/gui/block/CodeBlockView.kt index b3cb1d7204..458ed0ee20 100644 --- a/src/main/kotlin/com/intellij/temporary/gui/block/CodeBlockView.kt +++ b/src/main/kotlin/com/intellij/temporary/gui/block/CodeBlockView.kt @@ -38,7 +38,7 @@ import javax.swing.JComponent class CodeBlockView( private val block: CodeBlock, private val project: Project, - private val disposable: Disposable + private val disposable: Disposable, ) : MessageBlockView { private var editorInfo: CodePartEditorInfo? = null @@ -103,7 +103,7 @@ class CodeBlockView( project: Project, file: LightVirtualFile, document: Document, - disposable: Disposable + disposable: Disposable, ): EditorEx { val editor: EditorEx = ReadAction.compute { EditorFactory.getInstance() @@ -156,7 +156,7 @@ class CodeBlockView( graphProperty: GraphProperty, disposable: Disposable, language: Language, - message: CompletableMessage + message: CompletableMessage, ): CodePartEditorInfo { val forceFoldEditorByDefault = message.getRole() === ChatRole.User val createCodeViewerFile = createCodeViewerFile(language, graphProperty.get()) diff --git a/src/main/kotlin/com/intellij/temporary/gui/block/MessageBlock.kt b/src/main/kotlin/com/intellij/temporary/gui/block/MessageBlock.kt index 99fec11727..7f95d11be6 100644 --- a/src/main/kotlin/com/intellij/temporary/gui/block/MessageBlock.kt +++ b/src/main/kotlin/com/intellij/temporary/gui/block/MessageBlock.kt @@ -69,7 +69,7 @@ class CodeBlock(private val msg: CompletableMessage) : AbstractMessageBlock(msg) init { val language = Language.ANY - this.code = Code(language, "", false) + this.code = Code(language, msg.text, false) } override fun onContentChanged(content: String) { diff --git a/src/test/kotlin/cc/unitmesh/devti/parser/CodeUtilTest.kt b/src/test/kotlin/cc/unitmesh/devti/parser/CodeUtilTest.kt index 39c939c45d..532e2f11e9 100644 --- a/src/test/kotlin/cc/unitmesh/devti/parser/CodeUtilTest.kt +++ b/src/test/kotlin/cc/unitmesh/devti/parser/CodeUtilTest.kt @@ -21,13 +21,15 @@ class CodeUtilTest { val code = Code.parse(markdown) // assertEquals(code.language.id, "java") - assertEquals(code.text, """ + assertEquals( + code.text, """ |public class HelloWorld { | public static void main(String[] args) { | System.out.println("Hello, World"); | } |} - """.trimMargin()) + """.trimMargin() + ) assertTrue(code.isComplete) } @@ -41,11 +43,20 @@ class CodeUtilTest { """.trimMargin() val code = Code.parse(markdown) - assertEquals(code.text, """ + assertEquals( + code.text, """ |public class HelloWorld { | public static void main(String[] args) { | System.out.println("Hello, World"); - """.trimMargin()) + """.trimMargin() + ) assertTrue(!code.isComplete) } + + @Test + fun should_handle_pure_markdown_content() { + val content = "```markdown\\nGET /wp/v2/posts\\n```" + val code = Code.parse(content) + assertEquals(code.text, "GET /wp/v2/posts") + } } \ No newline at end of file