Skip to content

Commit de16193

Browse files
committed
add didRename
1 parent 8ee75f8 commit de16193

File tree

4 files changed

+160
-6
lines changed

4 files changed

+160
-6
lines changed

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ private class AmazonQServerInstance(private val project: Project, private val cs
211211
fileOperations = FileOperationsWorkspaceCapabilities().apply {
212212
didCreate = true
213213
didDelete = true
214+
didRename = true
214215
}
215216
}
216217
}

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/workspace/WorkspaceServiceHandler.kt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import com.intellij.openapi.vfs.newvfs.BulkFileListener
1313
import com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent
1414
import com.intellij.openapi.vfs.newvfs.events.VFileDeleteEvent
1515
import com.intellij.openapi.vfs.newvfs.events.VFileEvent
16+
import com.intellij.openapi.vfs.newvfs.events.VFilePropertyChangeEvent
1617
import org.eclipse.lsp4j.CreateFilesParams
1718
import org.eclipse.lsp4j.DeleteFilesParams
1819
import org.eclipse.lsp4j.DidChangeWatchedFilesParams
@@ -21,6 +22,8 @@ import org.eclipse.lsp4j.FileChangeType
2122
import org.eclipse.lsp4j.FileCreate
2223
import org.eclipse.lsp4j.FileDelete
2324
import org.eclipse.lsp4j.FileEvent
25+
import org.eclipse.lsp4j.FileRename
26+
import org.eclipse.lsp4j.RenameFilesParams
2427
import org.eclipse.lsp4j.WorkspaceFolder
2528
import org.eclipse.lsp4j.WorkspaceFoldersChangeEvent
2629
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
@@ -94,6 +97,36 @@ class WorkspaceServiceHandler(
9497
}
9598
}
9699

100+
private fun didRenameFiles(events: List<VFilePropertyChangeEvent>) {
101+
AmazonQLspService.executeIfRunning(project) { languageServer ->
102+
val validRenames = events
103+
.filter { it.propertyName == VirtualFile.PROP_NAME }
104+
.mapNotNull { event ->
105+
val file = event.file.takeIf { shouldHandleFile(it) } ?: return@mapNotNull null
106+
val oldName = event.oldValue as? String ?: return@mapNotNull null
107+
val newName = event.newValue as? String ?: return@mapNotNull null
108+
109+
// Construct old and new URIs
110+
val parentPath = file.parent?.toNioPath() ?: return@mapNotNull null
111+
val oldUri = parentPath.resolve(oldName).toUri().toString()
112+
val newUri = file.toNioPath().toUri().toString()
113+
114+
FileRename().apply {
115+
this.oldUri = oldUri
116+
this.newUri = newUri
117+
}
118+
}
119+
120+
if (validRenames.isNotEmpty()) {
121+
languageServer.workspaceService.didRenameFiles(
122+
RenameFilesParams().apply {
123+
files = validRenames
124+
}
125+
)
126+
}
127+
}
128+
}
129+
97130
private fun didChangeWatchedFiles(events: List<VFileEvent>) {
98131
AmazonQLspService.executeIfRunning(project) { languageServer ->
99132
val validChanges = events.mapNotNull { event ->
@@ -124,6 +157,7 @@ class WorkspaceServiceHandler(
124157
pluginAwareExecuteOnPooledThread {
125158
didCreateFiles(events.filterIsInstance<VFileCreateEvent>())
126159
didDeleteFiles(events.filterIsInstance<VFileDeleteEvent>())
160+
didRenameFiles(events.filterIsInstance<VFilePropertyChangeEvent>())
127161
didChangeWatchedFiles(events)
128162
}
129163
}

plugins/amazonq/shared/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/lsp/util/WorkspaceFolderUtilTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import com.intellij.openapi.roots.ProjectRootManager
88
import com.intellij.openapi.vfs.VirtualFile
99
import io.mockk.every
1010
import io.mockk.mockk
11-
import org.junit.Assert.assertEquals
12-
import org.junit.Test
11+
import org.junit.jupiter.api.Assertions.assertEquals
12+
import org.junit.jupiter.api.Test
1313

1414
class WorkspaceFolderUtilTest {
1515

plugins/amazonq/shared/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/lsp/workspace/WorkspaceServiceHandlerTest.kt

Lines changed: 123 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import com.intellij.openapi.vfs.VirtualFile
1212
import com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent
1313
import com.intellij.openapi.vfs.newvfs.events.VFileDeleteEvent
1414
import com.intellij.openapi.vfs.newvfs.events.VFileEvent
15+
import com.intellij.openapi.vfs.newvfs.events.VFilePropertyChangeEvent
1516
import com.intellij.util.messages.MessageBus
1617
import com.intellij.util.messages.MessageBusConnection
1718
import io.mockk.every
@@ -28,12 +29,13 @@ import org.eclipse.lsp4j.DeleteFilesParams
2829
import org.eclipse.lsp4j.DidChangeWatchedFilesParams
2930
import org.eclipse.lsp4j.DidChangeWorkspaceFoldersParams
3031
import org.eclipse.lsp4j.FileChangeType
32+
import org.eclipse.lsp4j.RenameFilesParams
3133
import org.eclipse.lsp4j.WorkspaceFolder
3234
import org.eclipse.lsp4j.jsonrpc.messages.ResponseMessage
3335
import org.eclipse.lsp4j.services.WorkspaceService
34-
import org.junit.Assert.assertEquals
35-
import org.junit.Before
36-
import org.junit.Test
36+
import org.junit.jupiter.api.Assertions.assertEquals
37+
import org.junit.jupiter.api.BeforeEach
38+
import org.junit.jupiter.api.Test
3739
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLanguageServer
3840
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
3941
import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.WorkspaceFolderUtil
@@ -49,7 +51,7 @@ class WorkspaceServiceHandlerTest {
4951
private lateinit var sut: WorkspaceServiceHandler
5052
private lateinit var mockApplication: Application
5153

52-
@Before
54+
@BeforeEach
5355
fun setup() {
5456
project = mockk<Project>()
5557
mockWorkspaceService = mockk<WorkspaceService>()
@@ -81,6 +83,7 @@ class WorkspaceServiceHandlerTest {
8183
every { mockLanguageServer.workspaceService } returns mockWorkspaceService
8284
every { mockWorkspaceService.didCreateFiles(any()) } returns Unit
8385
every { mockWorkspaceService.didDeleteFiles(any()) } returns Unit
86+
every { mockWorkspaceService.didRenameFiles(any()) } returns Unit
8487
every { mockWorkspaceService.didChangeWatchedFiles(any()) } returns Unit
8588
every { mockWorkspaceService.didChangeWorkspaceFolders(any()) } returns Unit
8689

@@ -270,6 +273,91 @@ class WorkspaceServiceHandlerTest {
270273
verify(exactly = 0) { mockWorkspaceService.didChangeWatchedFiles(any()) }
271274
}
272275

276+
@Test
277+
fun `test didRenameFiles with supported file`() = runTest {
278+
// Arrange
279+
val oldName = "oldFile.java"
280+
val newName = "newFile.java"
281+
val propertyEvent = createMockPropertyChangeEvent(
282+
oldName = oldName,
283+
newName = newName,
284+
isDirectory = false,
285+
extension = "java"
286+
)
287+
288+
// Act
289+
sut.after(listOf(propertyEvent))
290+
291+
// Assert
292+
val paramsSlot = slot<RenameFilesParams>()
293+
verify { mockWorkspaceService.didRenameFiles(capture(paramsSlot)) }
294+
with(paramsSlot.captured.files[0]) {
295+
assertEquals("file:///test/$oldName", oldUri)
296+
assertEquals("file:///test/$newName", newUri)
297+
}
298+
}
299+
300+
@Test
301+
fun `test didRenameFiles with unsupported file type`() = runTest {
302+
// Arrange
303+
val propertyEvent = createMockPropertyChangeEvent(
304+
oldName = "oldFile.txt",
305+
newName = "newFile.txt",
306+
isDirectory = false,
307+
extension = "txt"
308+
)
309+
310+
// Act
311+
sut.after(listOf(propertyEvent))
312+
313+
// Assert
314+
verify(exactly = 0) { mockWorkspaceService.didRenameFiles(any()) }
315+
}
316+
317+
@Test
318+
fun `test didRenameFiles with directory`() = runTest {
319+
// Arrange
320+
val propertyEvent = createMockPropertyChangeEvent(
321+
oldName = "oldDir",
322+
newName = "newDir",
323+
isDirectory = true
324+
)
325+
326+
// Act
327+
sut.after(listOf(propertyEvent))
328+
329+
// Assert
330+
val paramsSlot = slot<RenameFilesParams>()
331+
verify { mockWorkspaceService.didRenameFiles(capture(paramsSlot)) }
332+
with(paramsSlot.captured.files[0]) {
333+
assertEquals("file:///test/oldDir", oldUri)
334+
assertEquals("file:///test/newDir", newUri)
335+
}
336+
}
337+
338+
@Test
339+
fun `test didRenameFiles with multiple files`() = runTest {
340+
// Arrange
341+
val event1 = createMockPropertyChangeEvent(
342+
oldName = "old1.java",
343+
newName = "new1.java",
344+
extension = "java"
345+
)
346+
val event2 = createMockPropertyChangeEvent(
347+
oldName = "old2.py",
348+
newName = "new2.py",
349+
extension = "py"
350+
)
351+
352+
// Act
353+
sut.after(listOf(event1, event2))
354+
355+
// Assert
356+
val paramsSlot = slot<RenameFilesParams>()
357+
verify { mockWorkspaceService.didRenameFiles(capture(paramsSlot)) }
358+
assertEquals(2, paramsSlot.captured.files.size)
359+
}
360+
273361
@Test
274362
fun `rootsChanged does not notify when no changes`() = runTest {
275363
// Arrange
@@ -443,4 +531,35 @@ class WorkspaceServiceHandlerTest {
443531
every { file } returns virtualFile
444532
}
445533
}
534+
535+
// for didRename events
536+
private fun createMockPropertyChangeEvent(
537+
oldName: String,
538+
newName: String,
539+
isDirectory: Boolean = false,
540+
extension: String = "java",
541+
): VFilePropertyChangeEvent {
542+
val file = mockk<VirtualFile>()
543+
val parent = mockk<VirtualFile>()
544+
val parentPath = mockk<Path>()
545+
val filePath = mockk<Path>()
546+
547+
every { file.parent } returns parent
548+
every { parent.toNioPath() } returns parentPath
549+
every { file.toNioPath() } returns filePath
550+
every { file.isDirectory } returns isDirectory
551+
every { file.path } returns "/test/$newName"
552+
553+
every { parentPath.resolve(oldName) } returns mockk {
554+
every { toUri() } returns URI("file:///test/$oldName")
555+
}
556+
every { filePath.toUri() } returns URI("file:///test/$newName")
557+
558+
return mockk<VFilePropertyChangeEvent>().apply {
559+
every { propertyName } returns VirtualFile.PROP_NAME
560+
every { this@apply.file } returns file
561+
every { oldValue } returns oldName
562+
every { newValue } returns newName
563+
}
564+
}
446565
}

0 commit comments

Comments
 (0)