From 032d7ff6800bb003bd1e31303824fe05fc6dcb9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Kondratek?= Date: Wed, 7 Feb 2024 18:24:23 +0100 Subject: [PATCH] Add line ranges to the context files --- .../cody/agent/protocol/ContextFile.kt | 14 ++++- .../cody/chat/ui/ContextFilesPanel.kt | 55 ++++++++++++++----- 2 files changed, 53 insertions(+), 16 deletions(-) diff --git a/src/main/kotlin/com/sourcegraph/cody/agent/protocol/ContextFile.kt b/src/main/kotlin/com/sourcegraph/cody/agent/protocol/ContextFile.kt index ccf23c3a34..ebba4e2f43 100644 --- a/src/main/kotlin/com/sourcegraph/cody/agent/protocol/ContextFile.kt +++ b/src/main/kotlin/com/sourcegraph/cody/agent/protocol/ContextFile.kt @@ -1,6 +1,11 @@ package com.sourcegraph.cody.agent.protocol -import com.google.gson.* +import com.google.gson.GsonBuilder +import com.google.gson.JsonDeserializationContext +import com.google.gson.JsonDeserializer +import com.google.gson.JsonElement +import com.google.gson.JsonObject +import com.google.gson.JsonSerializer import java.lang.reflect.Type import java.net.URI @@ -15,6 +20,7 @@ data class ContextFileFile( override val uri: URI, override val repoName: String?, override val revision: String?, + val range: Range? = null, ) : ContextFile() { override val type: String = "file" } @@ -27,8 +33,8 @@ val contextFileDeserializer = val uri = context.deserialize(jsonObject["uri"], URI::class.java) val repoName = jsonObject["repoName"]?.asString val revision = jsonObject["revision"]?.asString - - ContextFileFile(uri, repoName, revision) + val range = gsonMapper.fromJson(jsonObject["range"], Range::class.java) + ContextFileFile(uri, repoName, revision, range) } // TODO(beyang): should throw an exception here, but we don't because the context field is @@ -37,6 +43,8 @@ val contextFileDeserializer = } } +private val gsonMapper = GsonBuilder().create() + val uriDeserializer = JsonDeserializer { jsonElement: JsonElement, typ: Type, context: JsonDeserializationContext -> val j = jsonElement.asJsonObject diff --git a/src/main/kotlin/com/sourcegraph/cody/chat/ui/ContextFilesPanel.kt b/src/main/kotlin/com/sourcegraph/cody/chat/ui/ContextFilesPanel.kt index 1e4bc659dd..b4039571d1 100644 --- a/src/main/kotlin/com/sourcegraph/cody/chat/ui/ContextFilesPanel.kt +++ b/src/main/kotlin/com/sourcegraph/cody/chat/ui/ContextFilesPanel.kt @@ -17,6 +17,7 @@ import com.intellij.util.withFragment import com.intellij.util.withQuery import com.sourcegraph.cody.agent.protocol.ChatMessage import com.sourcegraph.cody.agent.protocol.ContextFile +import com.sourcegraph.cody.agent.protocol.ContextFileFile import com.sourcegraph.cody.agent.protocol.Speaker import com.sourcegraph.cody.chat.ChatUIConstants.ASSISTANT_MESSAGE_GRADIENT_WIDTH import com.sourcegraph.cody.chat.ChatUIConstants.TEXT_MARGIN @@ -40,11 +41,16 @@ class ContextFilesPanel( } @RequiresBackgroundThread - private fun updateFileList(contextFileNames: Set) { + private fun updateFileList(contextFileNames: Map) { val filesAvailableInEditor = contextFileNames - .map(Paths::get) - .mapNotNull(VirtualFileManager.getInstance()::findFileByNioPath) + .map { + val path = Paths.get(it.key) + val findFileByNioPath = VirtualFileManager.getInstance().findFileByNioPath(path) + findFileByNioPath ?: return@map null + Pair(findFileByNioPath, it.value as? ContextFileFile) + } + .filterNotNull() .toList() ApplicationManager.getApplication().invokeLater { @@ -54,8 +60,8 @@ class ContextFilesPanel( val accordionSection = AccordionSection("Read ${filesAvailableInEditor.size} files") accordionSection.isOpaque = false accordionSection.border = EmptyBorder(margin) - filesAvailableInEditor.forEachIndexed { index, file: VirtualFile -> - val filePanel = createFileWithLinkPanel(file) + filesAvailableInEditor.forEachIndexed { index, file: Pair -> + val filePanel = createFileWithLinkPanel(file.first, file.second) accordionSection.contentPanel.add(filePanel, index) } add(accordionSection, BorderLayout.CENTER) @@ -63,7 +69,10 @@ class ContextFilesPanel( } @RequiresEdt - private fun createFileWithLinkPanel(file: VirtualFile): JPanel { + private fun createFileWithLinkPanel( + file: VirtualFile, + contextFileFile: ContextFileFile? + ): JPanel { val projectRelativeFilePath = file.path.removePrefix(project.basePath ?: "") val anAction = object : DumbAwareAction() { @@ -73,7 +82,8 @@ class ContextFilesPanel( FileEditorManager.getInstance(project).openFile(file, /*focusEditor=*/ true) } } - val goToFile = AnActionLink("@$projectRelativeFilePath", anAction) + val actionText = getActionTextForFileLinkAction(contextFileFile, projectRelativeFilePath) + val goToFile = AnActionLink(actionText, anAction) val panel = JPanel(BorderLayout()) panel.isOpaque = false panel.border = JBUI.Borders.emptyLeft(3) @@ -81,6 +91,22 @@ class ContextFilesPanel( return panel } + private fun getActionTextForFileLinkAction( + contextFileFile: ContextFileFile?, + projectRelativeFilePath: String + ): String { + val startLine = contextFileFile?.range?.start?.line + val endLine = contextFileFile?.range?.end?.line + return buildString { + append("@$projectRelativeFilePath") + if (startLine != null && endLine != null) { + if (startLine != endLine) { + append(":$startLine:$endLine") + } + } + } + } + fun updateContentWith(contextFiles: List?) { if (contextFiles.isNullOrEmpty()) { return @@ -89,13 +115,16 @@ class ContextFilesPanel( val contextFileNames = contextFiles .map { - if (it.repoName != null) { - "${project.basePath}/${it.uri.path}" - } else { - Paths.get(it.uri.withFragment(null).withQuery(null)).absolutePathString() - } + val contextFileName = + if (it.repoName != null) { + "${project.basePath}/${it.uri.path}" + } else { + val newUri = it.uri.withFragment(null).withQuery(null) + Paths.get(newUri).absolutePathString() + } + contextFileName to it } - .toSet() + .toMap() ApplicationManager.getApplication().executeOnPooledThread { updateFileList(contextFileNames) } }