@@ -7,10 +7,10 @@ import com.intellij.openapi.fileEditor.FileEditorManager
77import com.intellij.openapi.project.Project
88import com.intellij.openapi.roots.ProjectFileIndex
99import com.intellij.openapi.vfs.VirtualFile
10+ import com.intellij.openapi.vfs.isFile
1011import ee.carlrobert.codegpt.CodeGPTBundle
1112import ee.carlrobert.codegpt.ui.textarea.header.tag.FileTagDetails
1213import ee.carlrobert.codegpt.ui.textarea.header.tag.TagManager
13- import ee.carlrobert.codegpt.ui.textarea.header.tag.TagUtil
1414import ee.carlrobert.codegpt.ui.textarea.lookup.DynamicLookupGroupItem
1515import ee.carlrobert.codegpt.ui.textarea.lookup.LookupActionItem
1616import ee.carlrobert.codegpt.ui.textarea.lookup.LookupItem
@@ -28,36 +28,149 @@ class FilesGroupItem(
2828 override val icon = AllIcons .FileTypes .Any_type
2929
3030 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 > {
3139 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+ )
3780 }
38- items.size < 50
3981 }
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()
4194 }
4295 }
4396
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 ))
51114 }
52115
53116 private fun containsTag (file : VirtualFile ): Boolean {
54- return tagManager.containsTag(file)
117+ val tags = tagManager.getTags()
118+ return tags.contains(FileTagDetails (file))
55119 }
56120
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
62175 }
63176}
0 commit comments