@@ -8,16 +8,21 @@ import cc.unitmesh.devti.agent.model.CustomAgentState
88import cc.unitmesh.devti.llms.tokenizer.Tokenizer
99import cc.unitmesh.devti.llms.tokenizer.TokenizerFactory
1010import cc.unitmesh.devti.settings.AutoDevSettingsState
11+ import com.intellij.codeInsight.lookup.LookupManagerListener
12+ import com.intellij.icons.AllIcons
1113import com.intellij.ide.IdeTooltip
1214import com.intellij.ide.IdeTooltipManager
1315import com.intellij.openapi.Disposable
1416import com.intellij.openapi.actionSystem.AnActionEvent
1517import com.intellij.openapi.actionSystem.Presentation
1618import com.intellij.openapi.actionSystem.impl.ActionButton
19+ import com.intellij.openapi.application.ApplicationManager
1720import com.intellij.openapi.diagnostic.logger
1821import com.intellij.openapi.editor.event.DocumentEvent
1922import com.intellij.openapi.editor.event.DocumentListener
2023import com.intellij.openapi.editor.ex.EditorEx
24+ import com.intellij.openapi.fileEditor.FileEditorManagerEvent
25+ import com.intellij.openapi.fileEditor.FileEditorManagerListener
2126import com.intellij.openapi.project.DumbAwareAction
2227import com.intellij.openapi.project.Project
2328import com.intellij.openapi.ui.ComboBox
@@ -27,29 +32,30 @@ import com.intellij.openapi.ui.popup.Balloon.Position
2732import com.intellij.openapi.util.NlsContexts
2833import com.intellij.openapi.wm.IdeFocusManager
2934import com.intellij.openapi.wm.impl.InternalDecorator
35+ import com.intellij.psi.PsiElement
36+ import com.intellij.psi.PsiFile
37+ import com.intellij.psi.PsiManager
3038import com.intellij.temporary.gui.block.AutoDevCoolBorder
3139import com.intellij.ui.HintHint
3240import com.intellij.ui.MutableCollectionComboBoxModel
3341import com.intellij.ui.SimpleListCellRenderer
3442import com.intellij.ui.components.JBLabel
43+ import com.intellij.ui.components.JBList
44+ import com.intellij.ui.components.JBScrollPane
3545import com.intellij.util.EventDispatcher
3646import com.intellij.util.ui.JBEmptyBorder
3747import com.intellij.util.ui.JBUI
3848import com.intellij.util.ui.UIUtil
3949import com.intellij.util.ui.components.BorderLayoutPanel
40- import java.awt.CardLayout
41- import java.awt.Color
42- import java.awt.Dimension
43- import java.awt.Point
50+ import java.awt.*
4451import java.awt.event.MouseAdapter
4552import java.awt.event.MouseEvent
4653import java.util.function.Supplier
47- import javax.swing.Box
48- import javax.swing.JComponent
49- import javax.swing.JPanel
54+ import javax.swing.*
5055import kotlin.math.max
5156import kotlin.math.min
5257
58+ data class ModelWrapper (val psiElement : PsiElement , var panel : JPanel ? = null , var namePanel : JPanel ? = null )
5359/* *
5460 *
5561 */
@@ -62,6 +68,9 @@ class AutoDevInputSection(private val project: Project, val disposable: Disposab
6268 private val stopButton: ActionButton
6369 private val buttonPanel = JPanel (CardLayout ())
6470
71+ private val listModel = DefaultListModel <ModelWrapper >()
72+ private val elementsList = JBList (listModel)
73+
6574 private val defaultRag: CustomAgentConfig = CustomAgentConfig (" <Select Custom Agent>" , " Normal" )
6675 private var customRag: ComboBox <CustomAgentConfig > = ComboBox (MutableCollectionComboBoxModel (listOf ()))
6776
@@ -85,6 +94,7 @@ class AutoDevInputSection(private val project: Project, val disposable: Disposab
8594 }
8695
8796 init {
97+ setupElementsList()
8898 val sendButtonPresentation = Presentation (AutoDevBundle .message(" chat.panel.send" ))
8999 sendButtonPresentation.icon = AutoDevIcons .Send
90100 this .sendButtonPresentation = sendButtonPresentation
@@ -131,7 +141,10 @@ class AutoDevInputSection(private val project: Project, val disposable: Disposab
131141
132142 input.border = JBEmptyBorder (10 )
133143
134- addToCenter(input)
144+ // addToCenter(input)
145+ this .add(input, BorderLayout .CENTER )
146+ this .add(elementsList, BorderLayout .NORTH )
147+
135148 val layoutPanel = BorderLayoutPanel ()
136149 val horizontalGlue = Box .createHorizontalGlue()
137150 horizontalGlue.addMouseListener(object : MouseAdapter () {
@@ -174,6 +187,80 @@ class AutoDevInputSection(private val project: Project, val disposable: Disposab
174187 this @AutoDevInputSection.initEditor()
175188 }
176189 })
190+ setupEditorListener()
191+ setupRelatedListener()
192+ }
193+
194+ private fun setupEditorListener () {
195+ project.messageBus.connect(disposable!! ).subscribe(
196+ FileEditorManagerListener .FILE_EDITOR_MANAGER ,
197+ object : FileEditorManagerListener {
198+ override fun selectionChanged (event : FileEditorManagerEvent ) {
199+ val file = event.newFile ? : return
200+ val psiFile = PsiManager .getInstance(project).findFile(file) ? : return
201+ cc.unitmesh.devti.provider.RelatedClassesProvider .provide(psiFile.language) ? : return
202+ ApplicationManager .getApplication().invokeLater {
203+ listModel.addIfAbsent(psiFile)
204+ }
205+ }
206+ }
207+ )
208+ }
209+
210+ private fun setupRelatedListener () {
211+ project.messageBus.connect(disposable!! )
212+ .subscribe(LookupManagerListener .TOPIC , ShireInputLookupManagerListener (project) {
213+ ApplicationManager .getApplication().invokeLater {
214+ val relatedElements = cc.unitmesh.devti.provider.RelatedClassesProvider .provide(it.language)?.lookup(it)
215+ updateElements(relatedElements)
216+ }
217+ })
218+ }
219+
220+ private fun setupElementsList () {
221+ elementsList.selectionMode = ListSelectionModel .SINGLE_SELECTION
222+ elementsList.layoutOrientation = JList .HORIZONTAL_WRAP
223+ elementsList.visibleRowCount = 2
224+ elementsList.cellRenderer = RelatedFileListCellRenderer ()
225+ elementsList.setEmptyText(" " )
226+
227+ val scrollPane = JBScrollPane (elementsList)
228+ scrollPane.preferredSize = Dimension (- 1 , 80 )
229+ scrollPane.horizontalScrollBarPolicy = ScrollPaneConstants .HORIZONTAL_SCROLLBAR_ALWAYS
230+ scrollPane.verticalScrollBarPolicy = ScrollPaneConstants .VERTICAL_SCROLLBAR_AS_NEEDED
231+
232+ elementsList.addMouseListener(object : MouseAdapter () {
233+ override fun mouseClicked (e : MouseEvent ) {
234+ val list = e.source as JBList <* >
235+ val index = list.locationToIndex(e.point)
236+ if (index != - 1 ) {
237+ val wrapper = listModel.getElementAt(index)
238+ val cellBounds = list.getCellBounds(index, index)
239+ wrapper.panel?.components?.firstOrNull { it.contains(e.x - cellBounds.x - it.x, it.height - 1 ) }?.let {
240+ when {
241+ it is JPanel -> {
242+ listModel.removeElement(wrapper)
243+ wrapper.psiElement.containingFile?.let { psiFile ->
244+ val relativePath = psiFile.virtualFile.relativePath(project)
245+ input.appendText(" \n /" + " file" + " :${relativePath} " )
246+ listModel.indexOf(wrapper.psiElement).takeIf { it != - 1 }?.let { listModel.remove(it) }
247+ val relatedElements = cc.unitmesh.devti.provider.RelatedClassesProvider .provide(psiFile.language)?.lookup(psiFile)
248+ updateElements(relatedElements)
249+ }
250+ }
251+ it is JLabel && it.icon == AllIcons .Actions .Close -> listModel.removeElement(wrapper)
252+ else -> list.clearSelection()
253+ }
254+ } ? : list.clearSelection()
255+ }
256+ }
257+ })
258+
259+ add(scrollPane, BorderLayout .NORTH )
260+ }
261+
262+ private fun updateElements (elements : List <PsiElement >? ) {
263+ elements?.forEach { listModel.addIfAbsent(it) }
177264 }
178265
179266 fun showStopButton () {
@@ -290,3 +377,15 @@ class AutoDevInputSection(private val project: Project, val disposable: Disposab
290377
291378 val focusableComponent: JComponent get() = input
292379}
380+
381+ private fun DefaultListModel<ModelWrapper>.addIfAbsent (psiFile : PsiElement ) {
382+ val isValid = when (psiFile) {
383+ is PsiFile -> psiFile.isValid
384+ else -> true
385+ }
386+ if (! isValid) return
387+
388+ if (elements().asIterator().asSequence().none { it.psiElement == psiFile }) {
389+ addElement(ModelWrapper (psiFile))
390+ }
391+ }
0 commit comments