@@ -7,10 +7,10 @@ import com.intellij.openapi.fileEditor.FileEditorManager
7
7
import com.intellij.openapi.project.Project
8
8
import com.intellij.openapi.roots.ProjectFileIndex
9
9
import com.intellij.openapi.vfs.VirtualFile
10
+ import com.intellij.openapi.vfs.isFile
10
11
import ee.carlrobert.codegpt.CodeGPTBundle
11
12
import ee.carlrobert.codegpt.ui.textarea.header.tag.FileTagDetails
12
13
import ee.carlrobert.codegpt.ui.textarea.header.tag.TagManager
13
- import ee.carlrobert.codegpt.ui.textarea.header.tag.TagUtil
14
14
import ee.carlrobert.codegpt.ui.textarea.lookup.DynamicLookupGroupItem
15
15
import ee.carlrobert.codegpt.ui.textarea.lookup.LookupActionItem
16
16
import ee.carlrobert.codegpt.ui.textarea.lookup.LookupItem
@@ -28,36 +28,149 @@ class FilesGroupItem(
28
28
override val icon = AllIcons .FileTypes .Any_type
29
29
30
30
override suspend fun updateLookupItems (searchText : String ): List <LookupItem > {
31
+ return getFileItems(searchText)
32
+ }
33
+
34
+ override suspend fun getLookupItems (searchText : String ): List <LookupActionItem > {
35
+ return getFileItems(searchText)
36
+ }
37
+
38
+ private suspend fun getFileItems (searchText : String ): List <LookupActionItem > {
31
39
return withContext(Dispatchers .IO ) {
32
- val items = mutableListOf<LookupItem >()
33
- project.service<ProjectFileIndex >().iterateContent {
34
- if (! it.isDirectory && ! containsTag(it) &&
35
- (searchText.isEmpty() || it.name.contains(searchText, ignoreCase = true ))) {
36
- items.add(FileActionItem (project, it))
40
+ val fileEditorManager = project.service<FileEditorManager >()
41
+ val projectFileIndex = project.service<ProjectFileIndex >()
42
+
43
+ val (activeFiles, otherOpenFiles) = readAction {
44
+ val selectedFiles = fileEditorManager.selectedFiles.toList()
45
+ val openFiles = fileEditorManager.openFiles.toList()
46
+ val otherFiles = openFiles.filterNot { it in selectedFiles }
47
+
48
+ Pair (selectedFiles, otherFiles)
49
+ }
50
+
51
+ val filteredActiveFiles = activeFiles.filter { isValidFile(it, searchText, projectFileIndex) }
52
+ val filteredOpenFiles = otherOpenFiles.filter { isValidFile(it, searchText, projectFileIndex) }
53
+
54
+ val editorFilesCount = filteredActiveFiles.size + filteredOpenFiles.size
55
+ val needFromFileSystem = maxOf(0 , 30 - editorFilesCount)
56
+
57
+ val filesFromSystem = mutableListOf<VirtualFile >()
58
+ if (needFromFileSystem > 0 ) {
59
+ val editorFilesSet = (filteredActiveFiles + filteredOpenFiles).toSet()
60
+
61
+ readAction {
62
+ projectFileIndex.iterateContent(
63
+ /* processor = */ { file ->
64
+ if (filesFromSystem.size >= needFromFileSystem) {
65
+ false
66
+ } else {
67
+ if (! editorFilesSet.contains(file)) {
68
+ filesFromSystem.add(file)
69
+ }
70
+ true
71
+ }
72
+ },
73
+ /* filter = */ { file ->
74
+ ! file.isDirectory &&
75
+ isValidProjectFile(file, projectFileIndex) &&
76
+ ! containsTag(file) &&
77
+ (searchText.isEmpty() || file.name.contains(searchText, ignoreCase = true ))
78
+ }
79
+ )
37
80
}
38
- items.size < 50
39
81
}
40
- items
82
+
83
+ val allFiles = filteredActiveFiles + filteredOpenFiles + filesFromSystem
84
+
85
+ val result = allFiles
86
+ .map { FileActionItem (project, it) }
87
+ .toMutableList<LookupActionItem >()
88
+
89
+ if (searchText.isEmpty()) {
90
+ result.add(IncludeOpenFilesActionItem ())
91
+ }
92
+
93
+ result.toList()
41
94
}
42
95
}
43
96
44
- override suspend fun getLookupItems (searchText : String ): List <LookupActionItem > {
45
- return readAction {
46
- val projectFileIndex = project.service<ProjectFileIndex >()
47
- project.service<FileEditorManager >().openFiles
48
- .filter { projectFileIndex.isInContent(it) && ! containsTag(it) }
49
- .toFileSuggestions()
50
- }
97
+ private fun isValidProjectFile (file : VirtualFile , projectFileIndex : ProjectFileIndex ): Boolean {
98
+ return file.isFile &&
99
+ ! isExcludedFile(file) &&
100
+ projectFileIndex.isInContent(file) &&
101
+ ! projectFileIndex.isInLibraryClasses(file) &&
102
+ ! projectFileIndex.isInLibrarySource(file) &&
103
+ ! projectFileIndex.isInGeneratedSources(file)
104
+ }
105
+
106
+ private fun isExcludedFile (file : VirtualFile ): Boolean {
107
+ return file.extension?.lowercase() in EXCLUDED_EXTENSIONS
108
+ }
109
+
110
+ private fun isValidFile (file : VirtualFile , searchText : String , projectFileIndex : ProjectFileIndex ): Boolean {
111
+ return isValidProjectFile(file, projectFileIndex) &&
112
+ ! containsTag(file) &&
113
+ (searchText.isEmpty() || file.name.contains(searchText, ignoreCase = true ))
51
114
}
52
115
53
116
private fun containsTag (file : VirtualFile ): Boolean {
54
- return tagManager.containsTag(file)
117
+ val tags = tagManager.getTags()
118
+ return tags.contains(FileTagDetails (file))
55
119
}
56
120
57
- private fun Iterable<VirtualFile>.toFileSuggestions (): List <LookupActionItem > {
58
- val selectedFileTags = TagUtil .getExistingTags(project, FileTagDetails ::class .java)
59
- return filter { file -> selectedFileTags.none { it.virtualFile == file } }
60
- .take(10 )
61
- .map { FileActionItem (project, it) } + listOf (IncludeOpenFilesActionItem ())
121
+ private companion object {
122
+ val COMPILED_EXTENSIONS = setOf (
123
+ // Java/JVM languages
124
+ " class" , " jar" , " war" , " ear" , " aar" ,
125
+
126
+ // C/C++/Objective-C
127
+ " o" , " obj" , " so" , " dll" , " dylib" , " a" , " lib" , " framework" ,
128
+
129
+ // .NET/C#
130
+ " exe" , " pdb" , " mdb" ,
131
+
132
+ // Python
133
+ " pyc" , " pyo" , " pyd" ,
134
+
135
+ // Rust
136
+ " rlib" ,
137
+
138
+ // Go (compiled binaries often have no extension, but some cases)
139
+ " a" ,
140
+
141
+ // Android
142
+ " dex" , " apk" ,
143
+
144
+ // iOS
145
+ " ipa" ,
146
+
147
+ // Pascal/Delphi
148
+ " dcu" , " dcp" ,
149
+
150
+ // PHP
151
+ " phar" ,
152
+
153
+ // Archives and packages
154
+ " zip" , " tar" , " gz" , " bz2" , " xz" , " 7z" , " rar" ,
155
+
156
+ // Other binary formats
157
+ " bin" , " dat" , " dump"
158
+ )
159
+
160
+ val TEMPORARY_EXTENSIONS = setOf (
161
+ // Backup files
162
+ " bak" , " backup" , " tmp" , " temp" , " swp" , " swo" ,
163
+
164
+ // IDE/Editor temporary files
165
+ " idea" , " iml" , " ipr" , " iws" ,
166
+
167
+ // OS temporary files
168
+ " ds_store" , " thumbs.db" , " desktop.ini" ,
169
+
170
+ // Build artifacts
171
+ " log" , " cache"
172
+ )
173
+
174
+ val EXCLUDED_EXTENSIONS = COMPILED_EXTENSIONS + TEMPORARY_EXTENSIONS
62
175
}
63
176
}
0 commit comments