Skip to content

Commit 19cf4ba

Browse files
committed
feat(observer): enhance test error reporting and console editor handling #259
- Added `getConsoleEditor` method to retrieve and analyze console editor content. - Improved test error message formatting with markdown headers. - Added handling for IDEA interrupted code (255) in external task observer.
1 parent 855db60 commit 19cf4ba

File tree

2 files changed

+60
-5
lines changed

2 files changed

+60
-5
lines changed

core/src/main/kotlin/cc/unitmesh/devti/observer/ExternalTaskAgentObserver.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import com.intellij.util.messages.MessageBusConnection
1515

1616
class ExternalTaskAgentObserver : AgentObserver, Disposable {
1717
private var connection: MessageBusConnection? = null
18+
private val IDEA_INTERRUPTED_CODE = 255
1819

1920
override fun onRegister(project: Project) {
2021
connection = project.messageBus.connect()
@@ -48,7 +49,7 @@ class ExternalTaskAgentObserver : AgentObserver, Disposable {
4849
return
4950
}
5051

51-
if (exitCode != 0) {
52+
if (exitCode != 0 && exitCode != IDEA_INTERRUPTED_CODE) {
5253
val prompt = "Help Me fix follow build issue:\n```bash\n$globalBuffer\n```\n"
5354
sendErrorNotification(project, prompt)
5455
} else {

core/src/main/kotlin/cc/unitmesh/devti/observer/TestAgentObserver.kt

+58-4
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,25 @@ package cc.unitmesh.devti.observer
22

33
import cc.unitmesh.devti.provider.observer.AgentObserver
44
import cc.unitmesh.devti.util.relativePath
5+
import com.intellij.execution.impl.ConsoleViewImpl
56
import com.intellij.execution.testframework.sm.runner.SMTRunnerEventsAdapter
67
import com.intellij.execution.testframework.sm.runner.SMTRunnerEventsListener
78
import com.intellij.execution.testframework.sm.runner.SMTestProxy
9+
import com.intellij.execution.testframework.sm.runner.ui.SMTRunnerConsoleView
10+
import com.intellij.execution.ui.ExecutionConsole
11+
import com.intellij.execution.ui.RunContentManager
812
import com.intellij.openapi.Disposable
913
import com.intellij.openapi.application.runInEdt
1014
import com.intellij.openapi.application.runReadAction
15+
import com.intellij.openapi.editor.Editor
16+
import com.intellij.openapi.editor.markup.RangeHighlighter
1117
import com.intellij.openapi.project.Project
18+
import com.intellij.openapi.util.TextRange
1219
import com.intellij.psi.search.GlobalSearchScope
1320
import com.intellij.psi.search.ProjectScope
21+
import com.intellij.refactoring.suggested.range
1422
import com.intellij.util.messages.MessageBusConnection
23+
import java.lang.reflect.Field
1524

1625
class TestAgentObserver : AgentObserver, Disposable {
1726
private var connection: MessageBusConnection? = null
@@ -26,31 +35,76 @@ class TestAgentObserver : AgentObserver, Disposable {
2635

2736
private fun sendResult(test: SMTestProxy, project: Project, searchScope: GlobalSearchScope) {
2837
runInEdt {
38+
getConsoleEditor(project)
2939
val sourceCode = test.getLocation(project, searchScope)
3040
val psiElement = sourceCode?.psiElement
3141
val language = psiElement?.language?.displayName ?: ""
3242
val filepath = psiElement?.containingFile?.virtualFile?.relativePath(project) ?: ""
3343
val code = runReadAction<String> { psiElement?.text ?: "" }
3444
val prompt = """Help me fix follow test issue:
35-
| ErrorMessage:
45+
|## ErrorMessage:
3646
|```
3747
|${test.errorMessage}
3848
|```
39-
|stacktrace details:
49+
|## stacktrace details:
4050
|${test.stacktrace}
4151
|
42-
|// filepath: $filepath
52+
|## filepath: $filepath
4353
|origin code:
4454
|```$language
4555
|$code
4656
|```
4757
|""".trimMargin()
4858

49-
5059
sendErrorNotification(project, prompt)
5160
}
5261
}
5362

63+
/**
64+
*```kotlin
65+
* (content.component.components.firstOrNull() as? NonOpaquePanel)?.components?.firstOrNull { it is JBRunnerTabs }
66+
*```
67+
*/
68+
private fun getConsoleEditor(project: Project): Editor? {
69+
val content = RunContentManager.getInstance(project).selectedContent ?: return null
70+
val executionConsole = content.executionConsole ?: return null
71+
val consoleViewImpl: ConsoleViewImpl = getConsoleView(executionConsole) ?: return null
72+
val editor = consoleViewImpl.editor ?: return null
73+
74+
val startOffset = 0
75+
val allText = editor.document.text
76+
val endOffset = editor.document.textLength
77+
val textRange = TextRange(startOffset, endOffset)
78+
val highlighters: Array<RangeHighlighter> = editor.markupModel.allHighlighters
79+
80+
for (highlighter in highlighters) {
81+
if (textRange.contains(highlighter.range!!)) {
82+
// val hyperlinkInfo: FileHyperlinkInfo? = EditorHyperlinkSupport.getHyperlinkInfo(highlighter) as FileHyperlinkInfo
83+
// val descriptor = hyperlinkInfo?.descriptor ?: return null
84+
val range = highlighter.range!!
85+
val hyperlinkText = allText.substring(range.startOffset, range.endOffset)
86+
println("hyperlinkText: $hyperlinkText")
87+
}
88+
}
89+
90+
return consoleViewImpl.editor
91+
}
92+
93+
private fun getConsoleView(executionConsole: ExecutionConsole): ConsoleViewImpl? {
94+
if (executionConsole is SMTRunnerConsoleView) {
95+
try {
96+
val resultsViewerClass = executionConsole.resultsViewer::class.java
97+
val myConsoleViewField: Field = resultsViewerClass.getDeclaredField("myConsoleView")
98+
myConsoleViewField.isAccessible = true
99+
val myConsoleView = myConsoleViewField.get(executionConsole.resultsViewer) as? ConsoleViewImpl
100+
return myConsoleView
101+
} catch (e: Exception) {
102+
e.printStackTrace()
103+
}
104+
}
105+
return executionConsole as? ConsoleViewImpl
106+
}
107+
54108
override fun dispose() {
55109
connection?.disconnect()
56110
}

0 commit comments

Comments
 (0)