@@ -26,7 +26,9 @@ import org.eclipse.lsp4j.FileChangeType
26
26
import org.eclipse.lsp4j.FileCreate
27
27
import org.eclipse.lsp4j.FileDelete
28
28
import org.eclipse.lsp4j.FileEvent
29
+ import org.eclipse.lsp4j.FileOperationFilter
29
30
import org.eclipse.lsp4j.FileRename
31
+ import org.eclipse.lsp4j.InitializeResult
30
32
import org.eclipse.lsp4j.RenameFilesParams
31
33
import org.eclipse.lsp4j.TextDocumentIdentifier
32
34
import org.eclipse.lsp4j.TextDocumentItem
@@ -37,20 +39,22 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.FileUriUtil.toU
37
39
import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.WorkspaceFolderUtil.createWorkspaceFolders
38
40
import software.aws.toolkits.jetbrains.utils.pluginAwareExecuteOnPooledThread
39
41
import java.nio.file.FileSystems
42
+ import java.nio.file.PathMatcher
40
43
import java.nio.file.Paths
41
44
42
45
class WorkspaceServiceHandler (
43
46
private val project : Project ,
47
+ initializeResult : InitializeResult ,
44
48
serverInstance : Disposable ,
45
49
) : BulkFileListener,
46
50
ModuleRootListener {
47
51
48
52
private var lastSnapshot: List <WorkspaceFolder > = emptyList()
49
- private val supportedFilePatterns = FileSystems .getDefault().getPathMatcher(
50
- " glob:**/*.{ts,js,py,java}"
51
- )
53
+ private val operationMatchers: MutableMap <FileOperationType , List <Pair <PathMatcher , String >>> = mutableMapOf ()
52
54
53
55
init {
56
+ operationMatchers.putAll(initializePatterns(initializeResult))
57
+
54
58
project.messageBus.connect(serverInstance).subscribe(
55
59
VirtualFileManager .VFS_CHANGES ,
56
60
this
@@ -62,12 +66,46 @@ class WorkspaceServiceHandler(
62
66
)
63
67
}
64
68
69
+ enum class FileOperationType {
70
+ CREATE ,
71
+ DELETE ,
72
+ RENAME ,
73
+ }
74
+
75
+ private fun initializePatterns (initializeResult : InitializeResult ): Map <FileOperationType , List <Pair <PathMatcher , String >>> {
76
+ val patterns = mutableMapOf<FileOperationType , List <Pair <PathMatcher , String >>>()
77
+
78
+ initializeResult.capabilities?.workspace?.fileOperations?.let { fileOps ->
79
+ patterns[FileOperationType .CREATE ] = createMatchers(fileOps.didCreate?.filters)
80
+ patterns[FileOperationType .DELETE ] = createMatchers(fileOps.didDelete?.filters)
81
+ patterns[FileOperationType .RENAME ] = createMatchers(fileOps.didRename?.filters)
82
+ }
83
+
84
+ return patterns
85
+ }
86
+
87
+ private fun createMatchers (filters : List <FileOperationFilter >? ): List <Pair <PathMatcher , String >> =
88
+ filters?.map { filter ->
89
+ FileSystems .getDefault().getPathMatcher(" glob:${filter.pattern.glob} " ) to filter.pattern.matches
90
+ }.orEmpty()
91
+
92
+ private fun shouldHandleFile (file : VirtualFile , operation : FileOperationType ): Boolean {
93
+ val matchers = operationMatchers[operation] ? : return false
94
+ return matchers.any { (matcher, type) ->
95
+ when (type) {
96
+ " file" -> ! file.isDirectory && matcher.matches(Paths .get(file.path))
97
+ " folder" -> file.isDirectory && matcher.matches(Paths .get(file.path))
98
+ else -> matcher.matches(Paths .get(file.path))
99
+ }
100
+ }
101
+ }
102
+
65
103
private fun didCreateFiles (events : List <VFileEvent >) {
66
104
AmazonQLspService .executeIfRunning(project) { languageServer ->
67
105
val validFiles = events.mapNotNull { event ->
68
106
when (event) {
69
107
is VFileCopyEvent -> {
70
- val newFile = event.newParent.findChild(event.newChildName)?.takeIf { shouldHandleFile(it) }
108
+ val newFile = event.newParent.findChild(event.newChildName)?.takeIf { shouldHandleFile(it, FileOperationType . CREATE ) }
71
109
? : return @mapNotNull null
72
110
toUriString(newFile)?.let { uri ->
73
111
FileCreate ().apply {
@@ -76,7 +114,7 @@ class WorkspaceServiceHandler(
76
114
}
77
115
}
78
116
else -> {
79
- val file = event.file?.takeIf { shouldHandleFile(it) }
117
+ val file = event.file?.takeIf { shouldHandleFile(it, FileOperationType . CREATE ) }
80
118
? : return @mapNotNull null
81
119
toUriString(file)?.let { uri ->
82
120
FileCreate ().apply {
@@ -102,11 +140,11 @@ class WorkspaceServiceHandler(
102
140
val validFiles = events.mapNotNull { event ->
103
141
when (event) {
104
142
is VFileDeleteEvent -> {
105
- val file = event.file.takeIf { shouldHandleFile(it) } ? : return @mapNotNull null
143
+ val file = event.file.takeIf { shouldHandleFile(it, FileOperationType . DELETE ) } ? : return @mapNotNull null
106
144
toUriString(file)
107
145
}
108
146
is VFileMoveEvent -> {
109
- val oldFile = event.oldParent?.takeIf { shouldHandleFile(it) } ? : return @mapNotNull null
147
+ val oldFile = event.oldParent?.takeIf { shouldHandleFile(it, FileOperationType . DELETE ) } ? : return @mapNotNull null
110
148
toUriString(oldFile)
111
149
}
112
150
else -> null
@@ -132,7 +170,7 @@ class WorkspaceServiceHandler(
132
170
val validRenames = events
133
171
.filter { it.propertyName == VirtualFile .PROP_NAME }
134
172
.mapNotNull { event ->
135
- val renamedFile = event.file.takeIf { shouldHandleFile(it) } ? : return @mapNotNull null
173
+ val renamedFile = event.file.takeIf { shouldHandleFile(it, FileOperationType . RENAME ) } ? : return @mapNotNull null
136
174
val oldFileName = event.oldValue as ? String ? : return @mapNotNull null
137
175
val parentFile = renamedFile.parent ? : return @mapNotNull null
138
176
@@ -275,13 +313,4 @@ class WorkspaceServiceHandler(
275
313
lastSnapshot = currentSnapshot
276
314
}
277
315
}
278
-
279
- private fun shouldHandleFile (file : VirtualFile ): Boolean {
280
- if (file.isDirectory) {
281
- return true // Matches "**/*" with matches: "folder"
282
- }
283
- val path = Paths .get(file.path)
284
- val result = supportedFilePatterns.matches(path)
285
- return result
286
- }
287
316
}
0 commit comments