Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(amazonq): implement VirtualFile -> URI util for messaging params #5462

Open
wants to merge 11 commits into
base: feature/q-lsp
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import org.eclipse.lsp4j.TextDocumentIdentifier
import org.eclipse.lsp4j.TextDocumentItem
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.FileUriUtil.toUriString
import software.aws.toolkits.jetbrains.utils.pluginAwareExecuteOnPooledThread

class TextDocumentServiceHandler(
Expand Down Expand Up @@ -56,7 +57,7 @@ class TextDocumentServiceHandler(
override fun beforeDocumentSaving(document: Document) {
AmazonQLspService.executeIfRunning(project) { languageServer ->
val file = FileDocumentManager.getInstance().getFile(document) ?: return@executeIfRunning
file.toNioPath().toUri().toString().takeIf { it.isNotEmpty() }?.let { uri ->
toUriString(file)?.let { uri ->
languageServer.textDocumentService.didSave(
DidSaveTextDocumentParams().apply {
textDocument = TextDocumentIdentifier().apply {
Expand All @@ -74,7 +75,7 @@ class TextDocumentServiceHandler(
pluginAwareExecuteOnPooledThread {
events.filterIsInstance<VFileContentChangeEvent>().forEach { event ->
val document = FileDocumentManager.getInstance().getCachedDocument(event.file) ?: return@forEach
event.file.toNioPath().toUri().toString().takeIf { it.isNotEmpty() }?.let { uri ->
toUriString(event.file)?.let { uri ->
languageServer.textDocumentService.didChange(
DidChangeTextDocumentParams().apply {
textDocument = VersionedTextDocumentIdentifier().apply {
Expand All @@ -99,7 +100,7 @@ class TextDocumentServiceHandler(
file: VirtualFile,
) {
AmazonQLspService.executeIfRunning(project) { languageServer ->
file.toNioPath().toUri().toString().takeIf { it.isNotEmpty() }?.let { uri ->
toUriString(file)?.let { uri ->
languageServer.textDocumentService.didOpen(
DidOpenTextDocumentParams().apply {
textDocument = TextDocumentItem().apply {
Expand All @@ -117,7 +118,7 @@ class TextDocumentServiceHandler(
file: VirtualFile,
) {
AmazonQLspService.executeIfRunning(project) { languageServer ->
file.toNioPath().toUri().toString().takeIf { it.isNotEmpty() }?.let { uri ->
toUriString(file)?.let { uri ->
languageServer.textDocumentService.didClose(
DidCloseTextDocumentParams().apply {
textDocument = TextDocumentIdentifier().apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package software.aws.toolkits.jetbrains.services.amazonq.lsp.util
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootManager
import org.eclipse.lsp4j.WorkspaceFolder
import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.FileUriUtil.toUriString

object WorkspaceFolderUtil {
fun createWorkspaceFolders(project: Project): List<WorkspaceFolder> =
Expand All @@ -15,7 +16,7 @@ object WorkspaceFolderUtil {
ProjectRootManager.getInstance(project).contentRoots.map { contentRoot ->
WorkspaceFolder().apply {
name = contentRoot.name
this.uri = contentRoot.url
this.uri = toUriString(contentRoot)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import org.eclipse.lsp4j.RenameFilesParams
import org.eclipse.lsp4j.WorkspaceFolder
import org.eclipse.lsp4j.WorkspaceFoldersChangeEvent
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.FileUriUtil.toUriString
import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.WorkspaceFolderUtil.createWorkspaceFolders
import software.aws.toolkits.jetbrains.utils.pluginAwareExecuteOnPooledThread
import java.nio.file.FileSystems
Expand Down Expand Up @@ -59,7 +60,7 @@ class WorkspaceServiceHandler(
AmazonQLspService.executeIfRunning(project) { languageServer ->
val validFiles = events.mapNotNull { event ->
val file = event.file?.takeIf { shouldHandleFile(it) } ?: return@mapNotNull null
file.toNioPath().toUri().toString().takeIf { it.isNotEmpty() }?.let { uri ->
toUriString(file)?.let { uri ->
FileCreate().apply {
this.uri = uri
}
Expand All @@ -80,7 +81,7 @@ class WorkspaceServiceHandler(
AmazonQLspService.executeIfRunning(project) { languageServer ->
val validFiles = events.mapNotNull { event ->
val file = event.file?.takeIf { shouldHandleFile(it) } ?: return@mapNotNull null
file.toNioPath().toUri().toString().takeIf { it.isNotEmpty() }?.let { uri ->
toUriString(file)?.let { uri ->
FileDelete().apply {
this.uri = uri
}
Expand Down Expand Up @@ -109,7 +110,7 @@ class WorkspaceServiceHandler(
// Construct old and new URIs
val parentPath = file.parent?.toNioPath() ?: return@mapNotNull null
val oldUri = parentPath.resolve(oldName).toUri().toString()
val newUri = file.toNioPath().toUri().toString()
val newUri = toUriString(file)

FileRename().apply {
this.oldUri = oldUri
Expand All @@ -130,7 +131,7 @@ class WorkspaceServiceHandler(
private fun didChangeWatchedFiles(events: List<VFileEvent>) {
AmazonQLspService.executeIfRunning(project) { languageServer ->
val validChanges = events.mapNotNull { event ->
event.file?.toNioPath()?.toUri()?.toString()?.takeIf { it.isNotEmpty() }?.let { uri ->
event.file?.let { toUriString(it) }?.let { uri ->
FileEvent().apply {
this.uri = uri
type = when (event) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import com.intellij.util.messages.MessageBusConnection
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.mockkStatic
import io.mockk.runs
import io.mockk.slot
Expand All @@ -34,6 +35,7 @@ import org.junit.Before
import org.junit.Test
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLanguageServer
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.FileUriUtil
import java.net.URI
import java.nio.file.Path
import java.util.concurrent.Callable
Expand Down Expand Up @@ -99,14 +101,7 @@ class TextDocumentServiceHandlerTest {
every { text } returns "test content"
}

val path = mockk<Path> {
every { toUri() } returns uri
}

val file = mockk<VirtualFile> {
every { this@mockk.path } returns uri.path
every { toNioPath() } returns path
}
val file = createMockVirtualFile(uri)

// Mock FileDocumentManager
val fileDocumentManager = mockk<FileDocumentManager> {
Expand Down Expand Up @@ -136,17 +131,8 @@ class TextDocumentServiceHandlerTest {
// Create test file
val uri = URI.create("file:///test/path/file.txt")
val content = "test content"
val inputStream = content.byteInputStream()

val path = mockk<Path> {
every { toUri() } returns uri
}

val file = mockk<VirtualFile> {
every { this@mockk.path } returns uri.path
every { toNioPath() } returns path
every { this@mockk.inputStream } returns inputStream
}
val file = createMockVirtualFile(uri, content)

// Call the handler method
sut.fileOpened(mockk(), file)
Expand All @@ -164,13 +150,7 @@ class TextDocumentServiceHandlerTest {
@Test
fun `didClose runs on fileClosed`() = runTest {
val uri = URI.create("file:///test/path/file.txt")
val path = mockk<Path> {
every { toUri() } returns uri
}
val file = mockk<VirtualFile> {
every { this@mockk.path } returns uri.path
every { toNioPath() } returns path
}
val file = createMockVirtualFile(uri)

sut.fileClosed(mockk(), file)

Expand All @@ -188,14 +168,7 @@ class TextDocumentServiceHandlerTest {
every { modificationStamp } returns 123L
}

val path = mockk<Path> {
every { toUri() } returns uri
}

val file = mockk<VirtualFile> {
every { this@mockk.path } returns uri.path
every { toNioPath() } returns path
}
val file = createMockVirtualFile(uri)

val changeEvent = mockk<VFileContentChangeEvent> {
every { this@mockk.file } returns file
Expand Down Expand Up @@ -227,23 +200,22 @@ class TextDocumentServiceHandlerTest {
@Test
fun `didSave does not run when URI is empty`() = runTest {
val document = mockk<Document>()
val path = mockk<Path> {
every { toUri() } returns URI.create("")
}
val file = mockk<VirtualFile> {
every { toNioPath() } returns path
}
val file = createMockVirtualFile(URI.create(""))

val fileDocumentManager = mockk<FileDocumentManager> {
every { getFile(document) } returns file
}
mockkObject(FileUriUtil) {
every { FileUriUtil.toUriString(file) } returns null

mockkStatic(FileDocumentManager::class) {
every { FileDocumentManager.getInstance() } returns fileDocumentManager
val fileDocumentManager = mockk<FileDocumentManager> {
every { getFile(document) } returns file
}

sut.beforeDocumentSaving(document)
mockkStatic(FileDocumentManager::class) {
every { FileDocumentManager.getInstance() } returns fileDocumentManager

verify(exactly = 0) { mockTextDocumentService.didSave(any()) }
sut.beforeDocumentSaving(document)

verify(exactly = 0) { mockTextDocumentService.didSave(any()) }
}
}
}

Expand Down Expand Up @@ -298,4 +270,20 @@ class TextDocumentServiceHandlerTest {
verify(exactly = 0) { mockTextDocumentService.didChange(any()) }
}
}

private fun createMockVirtualFile(uri: URI, content: String = ""): VirtualFile {
val path = mockk<Path> {
every { toUri() } returns uri
}
val inputStream = content.byteInputStream()
return mockk<VirtualFile> {
every { url } returns uri.path
every { toNioPath() } returns path
every { isDirectory } returns false
every { fileSystem } returns mockk {
every { protocol } returns "file"
}
every { this@mockk.inputStream } returns inputStream
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -511,13 +511,18 @@ class WorkspaceServiceHandlerTest {
}

private fun createMockVFileEvent(uri: URI, type: FileChangeType = FileChangeType.Changed, isDirectory: Boolean, extension: String = "py"): VFileEvent {
val virtualFile = mockk<VirtualFile>()
val nioPath = mockk<Path>()

every { virtualFile.isDirectory } returns isDirectory
every { virtualFile.toNioPath() } returns nioPath
every { nioPath.toUri() } returns uri
every { virtualFile.path } returns "${uri.path}.$extension"
val nioPath = mockk<Path> {
every { toUri() } returns uri
}
val virtualFile = mockk<VirtualFile> {
every { this@mockk.isDirectory } returns isDirectory
every { toNioPath() } returns nioPath
every { url } returns uri.path
every { path } returns "${uri.path}.$extension"
every { fileSystem } returns mockk {
every { protocol } returns "file"
}
}

return when (type) {
FileChangeType.Deleted -> mockk<VFileDeleteEvent>()
Expand All @@ -544,6 +549,10 @@ class WorkspaceServiceHandlerTest {
every { file.toNioPath() } returns filePath
every { file.isDirectory } returns isDirectory
every { file.path } returns "/test/$newName"
every { file.url } returns "file:///test/$newName"
every { file.fileSystem } returns mockk {
every { protocol } returns "file"
}

every { parentPath.resolve(oldName) } returns mockk {
every { toUri() } returns URI("file:///test/$oldName")
Expand Down
Loading