feat: Added code structure analysis with depth configuration and improved tag handling (#1045)

* feat: add Kotlin inferred type analyzer

* feat: implemented a queue with support for maximum crawl depth

* feat: added the depth of analysis setting to end the chat

* feat: added the depth of analysis setting to code completion

* feat: add tag for code analysis

# Conflicts:
#	src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/PromptTextField.kt

* feat: changed priority of EditorTagDetails and FileTagDetails

If we added a file when opening a tab, and then added the same file through the "Include files in Prompt..." menu, it will not be in the selected state.

---------

Co-authored-by: alexander.korovin <alexander.korovin@vk.team>
Co-authored-by: Carl-Robert Linnupuu <carlrobertoh@gmail.com>
This commit is contained in:
Violine 2025-07-04 17:53:12 +03:00 committed by GitHub
parent 8306ac6d01
commit 846ecfeddc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 318 additions and 52 deletions

View file

@ -3,6 +3,7 @@ package ee.carlrobert.codegpt.toolwindow.chat.structure.data
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ReadAction
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer
@ -13,6 +14,7 @@ import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.util.io.await
import ee.carlrobert.codegpt.psistructure.PsiStructureProvider
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings
import ee.carlrobert.codegpt.settings.configuration.ConfigurationStateListener
import ee.carlrobert.codegpt.ui.textarea.header.tag.*
import ee.carlrobert.codegpt.util.coroutines.CoroutineDispatchers
@ -54,10 +56,29 @@ class PsiStructureRepository(
}
override fun onTagSelectionChanged(tag: TagDetails) {
(tag as? CodeAnalyzeTagDetails)?.let {
handleCodeAnalyzeTag(it)
}
val tags = tagManager.getTags().getPsiAnalyzedTags()
update(tags)
}
private fun handleCodeAnalyzeTag(tag: CodeAnalyzeTagDetails) {
if (!tag.selected) {
_structureState.value = PsiStructureState.Content(emptySet(), emptySet())
service<ConfigurationSettings>().state
.chatCompletionSettings
.psiStructureEnabled = false
disable()
} else {
service<ConfigurationSettings>().state
.chatCompletionSettings
.psiStructureEnabled = true
enable()
}
}
private fun updatePsiStructureIfNeeded() {
val tags = tagManager.getTags().getPsiAnalyzedTags()
if (isNeedUpdatePsiStructure(tags)) {
@ -99,6 +120,8 @@ class PsiStructureRepository(
}
}
private var analyzePsiDepth = Int.MAX_VALUE
init {
Disposer.register(parentDisposable, coroutineScope)
tagManager.addListener(tagsListener)
@ -113,7 +136,20 @@ class PsiStructureRepository(
connection.subscribe(
ConfigurationStateListener.TOPIC,
ConfigurationStateListener { newState ->
tagManager.getTags()
.filterIsInstance<CodeAnalyzeTagDetails>()
.forEach { tagManager.remove(it) }
if (tagManager.getTags().any { it is EditorTagDetails || it is FileTagDetails }) {
tagManager.addTag(
CodeAnalyzeTagDetails().apply {
selected = newState.chatCompletionSettings.psiStructureEnabled
}
)
}
if (newState.chatCompletionSettings.psiStructureEnabled) {
analyzePsiDepth = newState.chatCompletionSettings.psiStructureAnalyzeDepth
enable()
} else {
disable()
@ -164,7 +200,7 @@ class PsiStructureRepository(
.await()
val virtualFilesToRemoveFromStructure = tags.getExcludedVirtualFiles()
val result = psiStructureProvider.get(psiFiles)
val result = psiStructureProvider.get(psiFiles, analyzePsiDepth)
.filter { classStructure ->
!virtualFilesToRemoveFromStructure.contains(classStructure.virtualFile)
}
@ -197,8 +233,9 @@ class PsiStructureRepository(
is EmptyTagDetails -> null
is WebTagDetails -> null
is ImageTagDetails -> null
is CodeAnalyzeTagDetails -> null
}
virtualFile?.takeIf { it.isValid && it.exists()}
}
}
@ -223,6 +260,7 @@ class PsiStructureRepository(
is EmptyTagDetails -> false
is WebTagDetails -> false
is ImageTagDetails -> false
is CodeAnalyzeTagDetails -> false
}
}
.toSet()
@ -249,8 +287,9 @@ class PsiStructureRepository(
is EmptyTagDetails -> null
is WebTagDetails -> null
is ImageTagDetails -> null
is CodeAnalyzeTagDetails -> null
}
virtualFile?.takeIf { it.isValid && it.exists()}
}
}

View file

@ -63,6 +63,8 @@ public class TotalTokensPanel extends JPanel {
if (ConfigurationSettings.getState().getChatCompletionSettings()
.getPsiStructureEnabled()) {
updatePsiTokenCount(psiTokens);
} else {
updatePsiTokenCount(0);
}
return Unit.INSTANCE;
}