11package ee.carlrobert.codegpt.ui.textarea
22
3+ import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl
4+ import com.intellij.codeInsight.daemon.impl.HighlightInfo
5+ import com.intellij.lang.annotation.HighlightSeverity
36import com.intellij.openapi.components.service
7+ import com.intellij.openapi.fileEditor.FileDocumentManager
48import com.intellij.openapi.progress.ProgressManager
9+ import com.intellij.openapi.project.DumbService
510import com.intellij.openapi.project.Project
11+ import com.intellij.openapi.util.text.StringUtil
612import com.intellij.openapi.vfs.VirtualFile
13+ import com.intellij.psi.PsiDocumentManager
14+ import com.intellij.psi.PsiManager
715import ee.carlrobert.codegpt.EncodingManager
816import ee.carlrobert.codegpt.completions.CompletionRequestUtil
917import ee.carlrobert.codegpt.conversations.Conversation
@@ -33,6 +41,7 @@ object TagProcessorFactory {
3341 is ImageTagDetails -> ImageTagProcessor (tagDetails)
3442 is EmptyTagDetails -> TagProcessor { _, _ -> }
3543 is CodeAnalyzeTagDetails -> TagProcessor { _, _ -> }
44+ is DiagnosticsTagDetails -> DiagnosticsTagProcessor (project, tagDetails)
3645 }
3746 }
3847}
@@ -248,4 +257,116 @@ class ConversationTagProcessor(
248257 }
249258 message.conversationsHistoryIds?.add(tagDetails.conversationId)
250259 }
260+ }
261+
262+ class DiagnosticsTagProcessor (
263+ private val project : Project ,
264+ private val tagDetails : DiagnosticsTagDetails ,
265+ ) : TagProcessor {
266+ override fun process (message : Message , promptBuilder : StringBuilder ) {
267+ promptBuilder
268+ .append(" \n ## Current File Problems\n " )
269+ .append(getDiagnosticsString(project, tagDetails.virtualFile))
270+ .append(" \n " )
271+ }
272+
273+ private fun getDiagnosticsString (project : Project , virtualFile : VirtualFile ): String {
274+ return try {
275+ DumbService .getInstance(project).runReadActionInSmartMode<String > {
276+ val document = FileDocumentManager .getInstance().getDocument(virtualFile)
277+ ? : return @runReadActionInSmartMode " No document found for file"
278+
279+ PsiDocumentManager .getInstance(project).commitDocument(document)
280+
281+ val psiManager = PsiManager .getInstance(project)
282+ val psiFile = psiManager.findFile(virtualFile)
283+ ? : return @runReadActionInSmartMode " No PSI file found for: ${virtualFile.path} "
284+
285+ val rangeHighlights =
286+ DaemonCodeAnalyzerImpl .getHighlights(
287+ document,
288+ HighlightSeverity .WEAK_WARNING ,
289+ project
290+ )
291+ // TODO: Find a better solution
292+ val fileLevel: List <HighlightInfo > = try {
293+ val method = DaemonCodeAnalyzerImpl ::class .java.methods.firstOrNull {
294+ it.name == " getFileLevelHighlights" && it.parameterCount == 2
295+ }
296+ if (method != null ) {
297+ @Suppress(" UNCHECKED_CAST" )
298+ method.invoke(null , project, psiFile) as ? List <HighlightInfo > ? : emptyList()
299+ } else {
300+ emptyList()
301+ }
302+ } catch (_: Throwable ) {
303+ emptyList()
304+ }
305+
306+ val highlights = (rangeHighlights.asSequence() + fileLevel.asSequence())
307+ .distinctBy { Triple (it.description, it.startOffset, it.severity) }
308+ .sortedWith(
309+ compareBy<HighlightInfo >(
310+ { severityOrder(it.severity) },
311+ { it.startOffset.coerceAtLeast(0 ) }
312+ )
313+ )
314+ .toList()
315+
316+ if (highlights.isEmpty()) {
317+ return @runReadActionInSmartMode " "
318+ }
319+
320+ val maxItems = 200
321+ val overflow = (highlights.size - maxItems).coerceAtLeast(0 )
322+ val shown = highlights.take(maxItems)
323+
324+ buildString {
325+ append(" File: ${virtualFile.name} \n " )
326+ append(" Path: ${virtualFile.path} \n\n " )
327+
328+ shown.forEach { info ->
329+ val startOffset = info.startOffset.coerceIn(0 , document.textLength)
330+ val lineColText =
331+ if (info.startOffset >= 0 && document.textLength > 0 ) {
332+ val line = document.getLineNumber(startOffset) + 1
333+ val col = startOffset - document.getLineStartOffset(line - 1 ) + 1
334+ " line $line , col $col "
335+ } else {
336+ " file-level"
337+ }
338+
339+ val rawMessage = info.description ? : info.toolTip ? : " "
340+ val message = StringUtil .removeHtmlTags(rawMessage, false ).trim()
341+
342+ val severityLabel = when (info.severity) {
343+ HighlightSeverity .ERROR -> " ERROR"
344+ HighlightSeverity .WARNING -> " WARNING"
345+ HighlightSeverity .WEAK_WARNING -> " WEAK_WARNING"
346+ HighlightSeverity .INFORMATION -> " INFO"
347+ else -> info.severity.toString()
348+ }
349+
350+ append(" - [$severityLabel ] $lineColText : $message \n " )
351+ }
352+
353+ if (overflow > 0 ) {
354+ append(" ... ($overflow more not shown)\n " )
355+ }
356+ }
357+ }
358+ } catch (e: Exception ) {
359+ " Error retrieving diagnostics: ${e.message} "
360+ }
361+ }
362+
363+ private fun severityOrder (severity : HighlightSeverity ): Int {
364+ return when (severity) {
365+ HighlightSeverity .ERROR -> 0
366+ HighlightSeverity .WARNING -> 1
367+ HighlightSeverity .WEAK_WARNING -> 2
368+ HighlightSeverity .INFORMATION -> 3
369+ else -> 4
370+ }
371+ }
251372}
0 commit comments