@@ -8,16 +8,21 @@ import cc.unitmesh.devti.agent.model.CustomAgentState
8
8
import cc.unitmesh.devti.llms.tokenizer.Tokenizer
9
9
import cc.unitmesh.devti.llms.tokenizer.TokenizerFactory
10
10
import cc.unitmesh.devti.settings.AutoDevSettingsState
11
+ import com.intellij.codeInsight.lookup.LookupManagerListener
12
+ import com.intellij.icons.AllIcons
11
13
import com.intellij.ide.IdeTooltip
12
14
import com.intellij.ide.IdeTooltipManager
13
15
import com.intellij.openapi.Disposable
14
16
import com.intellij.openapi.actionSystem.AnActionEvent
15
17
import com.intellij.openapi.actionSystem.Presentation
16
18
import com.intellij.openapi.actionSystem.impl.ActionButton
19
+ import com.intellij.openapi.application.ApplicationManager
17
20
import com.intellij.openapi.diagnostic.logger
18
21
import com.intellij.openapi.editor.event.DocumentEvent
19
22
import com.intellij.openapi.editor.event.DocumentListener
20
23
import com.intellij.openapi.editor.ex.EditorEx
24
+ import com.intellij.openapi.fileEditor.FileEditorManagerEvent
25
+ import com.intellij.openapi.fileEditor.FileEditorManagerListener
21
26
import com.intellij.openapi.project.DumbAwareAction
22
27
import com.intellij.openapi.project.Project
23
28
import com.intellij.openapi.ui.ComboBox
@@ -27,29 +32,30 @@ import com.intellij.openapi.ui.popup.Balloon.Position
27
32
import com.intellij.openapi.util.NlsContexts
28
33
import com.intellij.openapi.wm.IdeFocusManager
29
34
import com.intellij.openapi.wm.impl.InternalDecorator
35
+ import com.intellij.psi.PsiElement
36
+ import com.intellij.psi.PsiFile
37
+ import com.intellij.psi.PsiManager
30
38
import com.intellij.temporary.gui.block.AutoDevCoolBorder
31
39
import com.intellij.ui.HintHint
32
40
import com.intellij.ui.MutableCollectionComboBoxModel
33
41
import com.intellij.ui.SimpleListCellRenderer
34
42
import com.intellij.ui.components.JBLabel
43
+ import com.intellij.ui.components.JBList
44
+ import com.intellij.ui.components.JBScrollPane
35
45
import com.intellij.util.EventDispatcher
36
46
import com.intellij.util.ui.JBEmptyBorder
37
47
import com.intellij.util.ui.JBUI
38
48
import com.intellij.util.ui.UIUtil
39
49
import 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.*
44
51
import java.awt.event.MouseAdapter
45
52
import java.awt.event.MouseEvent
46
53
import java.util.function.Supplier
47
- import javax.swing.Box
48
- import javax.swing.JComponent
49
- import javax.swing.JPanel
54
+ import javax.swing.*
50
55
import kotlin.math.max
51
56
import kotlin.math.min
52
57
58
+ data class ModelWrapper (val psiElement : PsiElement , var panel : JPanel ? = null , var namePanel : JPanel ? = null )
53
59
/* *
54
60
*
55
61
*/
@@ -62,6 +68,9 @@ class AutoDevInputSection(private val project: Project, val disposable: Disposab
62
68
private val stopButton: ActionButton
63
69
private val buttonPanel = JPanel (CardLayout ())
64
70
71
+ private val listModel = DefaultListModel <ModelWrapper >()
72
+ private val elementsList = JBList (listModel)
73
+
65
74
private val defaultRag: CustomAgentConfig = CustomAgentConfig (" <Select Custom Agent>" , " Normal" )
66
75
private var customRag: ComboBox <CustomAgentConfig > = ComboBox (MutableCollectionComboBoxModel (listOf ()))
67
76
@@ -85,6 +94,7 @@ class AutoDevInputSection(private val project: Project, val disposable: Disposab
85
94
}
86
95
87
96
init {
97
+ setupElementsList()
88
98
val sendButtonPresentation = Presentation (AutoDevBundle .message(" chat.panel.send" ))
89
99
sendButtonPresentation.icon = AutoDevIcons .Send
90
100
this .sendButtonPresentation = sendButtonPresentation
@@ -131,7 +141,10 @@ class AutoDevInputSection(private val project: Project, val disposable: Disposab
131
141
132
142
input.border = JBEmptyBorder (10 )
133
143
134
- addToCenter(input)
144
+ // addToCenter(input)
145
+ this .add(input, BorderLayout .CENTER )
146
+ this .add(elementsList, BorderLayout .NORTH )
147
+
135
148
val layoutPanel = BorderLayoutPanel ()
136
149
val horizontalGlue = Box .createHorizontalGlue()
137
150
horizontalGlue.addMouseListener(object : MouseAdapter () {
@@ -174,6 +187,80 @@ class AutoDevInputSection(private val project: Project, val disposable: Disposab
174
187
this @AutoDevInputSection.initEditor()
175
188
}
176
189
})
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) }
177
264
}
178
265
179
266
fun showStopButton () {
@@ -290,3 +377,15 @@ class AutoDevInputSection(private val project: Project, val disposable: Disposab
290
377
291
378
val focusableComponent: JComponent get() = input
292
379
}
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