Skip to content

Commit a7c114d

Browse files
author
C Tidd
committed
feat(amazonq): Add support for multi-project workspaces.
1 parent e6f3806 commit a7c114d

File tree

19 files changed

+260
-187
lines changed

19 files changed

+260
-187
lines changed

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/common/session/SessionStateTypes.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
package software.aws.toolkits.jetbrains.common.session
55

66
import software.aws.toolkits.jetbrains.common.util.AmazonQCodeGenService
7-
import software.aws.toolkits.jetbrains.services.amazonq.FeatureDevSessionContext
7+
import software.aws.toolkits.jetbrains.services.amazonq.project.FeatureDevSessionContext
88

99
open class SessionStateConfig(
1010
open val conversationId: String,

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/controller/DocController.kt

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ import software.aws.toolkits.core.utils.info
3131
import software.aws.toolkits.core.utils.warn
3232
import software.aws.toolkits.jetbrains.common.util.selectFolder
3333
import software.aws.toolkits.jetbrains.core.coroutines.EDT
34-
import software.aws.toolkits.jetbrains.services.amazonq.RepoSizeError
3534
import software.aws.toolkits.jetbrains.services.amazonq.apps.AmazonQAppInitContext
3635
import software.aws.toolkits.jetbrains.services.amazonq.auth.AuthController
36+
import software.aws.toolkits.jetbrains.services.amazonq.project.RepoSizeError
3737
import software.aws.toolkits.jetbrains.services.amazonq.toolwindow.AmazonQToolWindowFactory
3838
import software.aws.toolkits.jetbrains.services.amazonqDoc.DEFAULT_RETRY_LIMIT
3939
import software.aws.toolkits.jetbrains.services.amazonqDoc.DIAGRAM_SVG_EXT
@@ -83,6 +83,7 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcas
8383
import software.aws.toolkits.resources.message
8484
import java.nio.file.Paths
8585
import java.util.UUID
86+
import kotlin.io.path.pathString
8687

8788
enum class DocGenerationStep {
8889
UPLOAD_TO_S3,
@@ -308,7 +309,7 @@ class DocController(
308309
private suspend fun promptForDocTarget(tabId: String) {
309310
val session = getSessionInfo(tabId)
310311

311-
val currentSourceFolder = session.context.selectedSourceFolder
312+
val currentSourceFolder = session.context.selectedRoot
312313

313314
try {
314315
messenger.sendFolderConfirmationMessage(
@@ -405,7 +406,7 @@ class DocController(
405406
inMemoryFile.isWritable = false
406407
FileEditorManager.getInstance(context.project).openFile(inMemoryFile, true)
407408
} else {
408-
val existingFile = VfsUtil.findRelativeFile(message.filePath, session.context.selectedSourceFolder)
409+
val existingFile = VfsUtil.findRelativeFile(message.filePath, session.context.selectedRoot)
409410
val leftDiffContent = if (existingFile == null) {
410411
EmptyContent()
411412
} else {
@@ -952,8 +953,8 @@ class DocController(
952953

953954
private suspend fun modifyDefaultSourceFolder(tabId: String) {
954955
val session = getSessionInfo(tabId)
955-
val currentSourceFolder = session.context.selectedSourceFolder
956-
val projectRoot = session.context.projectRoot
956+
val currentSourceFolder = session.context.selectedRoot
957+
val workspaceRoot = session.context.workspaceRoot
957958

958959
withContext(EDT) {
959960
messenger.sendAnswer(
@@ -999,15 +1000,15 @@ class DocController(
9991000
return@withContext
10001001
}
10011002

1002-
if (selectedFolder.path == projectRoot.path) {
1003+
if (selectedFolder.path == workspaceRoot.pathString) {
10031004
docGenerationTask.folderLevel = DocFolderLevel.ENTIRE_WORKSPACE
10041005
} else {
10051006
docGenerationTask.folderLevel = DocFolderLevel.SUB_FOLDER
10061007
}
10071008

10081009
logger.info { "Selected correct folder inside workspace: ${selectedFolder.path}" }
10091010

1010-
session.context.selectedSourceFolder = selectedFolder
1011+
session.context.selectedRoot = selectedFolder
10111012

10121013
promptForDocTarget(tabId)
10131014

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/session/DocSession.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,14 @@ class DocSession(val tabID: String, val project: Project) {
107107
* Triggered by the Insert code follow-up button to apply code changes.
108108
*/
109109
fun insertChanges(filePaths: List<NewFileZipInfo>, deletedFiles: List<DeletedFileInfo>) {
110-
val selectedSourceFolder = context.selectedSourceFolder.toNioPath()
110+
val selectedSourceFolder = context.selectedRoot
111111

112-
filePaths.forEach { resolveAndCreateOrUpdateFile(selectedSourceFolder, it.zipFilePath, it.fileContent) }
112+
filePaths.forEach { resolveAndCreateOrUpdateFile(selectedSourceFolder.toNioPath(), it.zipFilePath, it.fileContent) }
113113

114-
deletedFiles.forEach { resolveAndDeleteFile(selectedSourceFolder, it.zipFilePath) }
114+
deletedFiles.forEach { resolveAndDeleteFile(selectedSourceFolder.toNioPath(), it.zipFilePath) }
115115

116116
// Taken from https://intellij-support.jetbrains.com/hc/en-us/community/posts/206118439-Refresh-after-external-changes-to-project-structure-and-sources
117-
VfsUtil.markDirtyAndRefresh(true, true, true, context.selectedSourceFolder)
117+
VfsUtil.markDirtyAndRefresh(true, true, true, context.selectedRoot)
118118
}
119119

120120
private fun getFromReportedChanges(filePath: NewFileZipInfo): String? {
@@ -158,7 +158,7 @@ class DocSession(val tabID: String, val project: Project) {
158158
}
159159
} else {
160160
val sourceContent = reportedChange
161-
?: VfsUtil.findRelativeFile(filePath.zipFilePath, context.selectedSourceFolder)?.content()
161+
?: VfsUtil.findRelativeFile(filePath.zipFilePath, context.selectedRoot)?.content()
162162
.orEmpty()
163163
val diffMetrics = getDiffMetrics(sourceContent, content)
164164
totalAddedLines += diffMetrics.insertedLines
@@ -185,7 +185,7 @@ class DocSession(val tabID: String, val project: Project) {
185185
totalAddedChars += content.length
186186
totalAddedLines += content.split('\n').size
187187
} else {
188-
val existingFileContent = VfsUtil.findRelativeFile(filePath.zipFilePath, context.selectedSourceFolder)?.content()
188+
val existingFileContent = VfsUtil.findRelativeFile(filePath.zipFilePath, context.selectedRoot)?.content()
189189
val diffMetrics = getDiffMetrics(existingFileContent.orEmpty(), content)
190190
totalAddedLines += diffMetrics.insertedLines
191191
totalAddedChars += diffMetrics.insertedCharacters

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/session/DocSessionContext.kt

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,11 @@ package software.aws.toolkits.jetbrains.services.amazonqDoc.session
55

66
import com.intellij.openapi.project.Project
77
import com.intellij.openapi.vfs.VirtualFile
8-
import software.aws.toolkits.jetbrains.services.amazonq.FeatureDevSessionContext
8+
import software.aws.toolkits.jetbrains.services.amazonq.project.FeatureDevSessionContext
99
import software.aws.toolkits.jetbrains.services.amazonqDoc.SUPPORTED_DIAGRAM_EXT_SET
1010
import software.aws.toolkits.jetbrains.services.amazonqDoc.SUPPORTED_DIAGRAM_FILE_NAME_SET
1111

1212
class DocSessionContext(project: Project, maxProjectSizeBytes: Long? = null) : FeatureDevSessionContext(project, maxProjectSizeBytes) {
13-
14-
/**
15-
* Ensure diagram files are not ignored
16-
*/
17-
override fun getAdditionalGitIgnoreBinaryFilesRules(): Set<String> {
18-
val ignoreRules = super.getAdditionalGitIgnoreBinaryFilesRules()
19-
val diagramExtRulesInGitIgnoreFormatSet = SUPPORTED_DIAGRAM_EXT_SET.map { "*.$it" }.toSet()
20-
return ignoreRules - diagramExtRulesInGitIgnoreFormatSet
21-
}
22-
23-
/**
24-
* Ensure diagram files are not filtered
25-
*/
26-
override fun isFileExtensionAllowed(file: VirtualFile): Boolean {
27-
if (super.isFileExtensionAllowed(file)) {
28-
return true
29-
}
30-
31-
return file.extension != null && SUPPORTED_DIAGRAM_FILE_NAME_SET.contains(file.name)
32-
}
13+
override fun shouldIncludeFileIfNoExplicitIgnore(file: VirtualFile): Boolean =
14+
SUPPORTED_DIAGRAM_EXT_SET.any { file.path.endsWith(it) } || SUPPORTED_DIAGRAM_FILE_NAME_SET.contains(file.name)
3315
}

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/FeatureDevExceptions.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
package software.aws.toolkits.jetbrains.services.amazonqFeatureDev
55

6-
import software.aws.toolkits.jetbrains.services.amazonq.RepoSizeError
6+
import software.aws.toolkits.jetbrains.services.amazonq.project.RepoSizeError
77
import software.aws.toolkits.resources.message
88

99
/**

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/controller/FeatureDevController.kt

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ import software.aws.toolkits.core.utils.info
2929
import software.aws.toolkits.core.utils.warn
3030
import software.aws.toolkits.jetbrains.common.util.selectFolder
3131
import software.aws.toolkits.jetbrains.core.coroutines.EDT
32-
import software.aws.toolkits.jetbrains.services.amazonq.RepoSizeError
3332
import software.aws.toolkits.jetbrains.services.amazonq.apps.AmazonQAppInitContext
3433
import software.aws.toolkits.jetbrains.services.amazonq.auth.AuthController
3534
import software.aws.toolkits.jetbrains.services.amazonq.messages.MessagePublisher
35+
import software.aws.toolkits.jetbrains.services.amazonq.project.RepoSizeError
3636
import software.aws.toolkits.jetbrains.services.amazonq.toolwindow.AmazonQToolWindowFactory
3737
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.CodeIterationLimitException
3838
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.DEFAULT_RETRY_LIMIT
@@ -87,6 +87,7 @@ import software.aws.toolkits.telemetry.AmazonqTelemetry
8787
import software.aws.toolkits.telemetry.Result
8888
import software.aws.toolkits.telemetry.UiTelemetry
8989
import java.util.UUID
90+
import kotlin.io.path.pathString
9091

9192
class FeatureDevController(
9293
private val context: AmazonQAppInitContext,
@@ -249,7 +250,7 @@ class FeatureDevController(
249250
when (sessionState) {
250251
is PrepareCodeGenerationState -> {
251252
runInEdt {
252-
val existingFile = VfsUtil.findRelativeFile(message.filePath, session.context.selectedSourceFolder)
253+
val existingFile = VfsUtil.findRelativeFile(message.filePath, session.context.selectedRoot)
253254

254255
val leftDiffContent = if (existingFile == null) {
255256
EmptyContent()
@@ -336,7 +337,7 @@ class FeatureDevController(
336337
var pollAttempt = 0
337338
val pollDelayMs = 10L
338339
while (pollAttempt < 5) {
339-
val file = VfsUtil.findRelativeFile(message.filePath, session.context.selectedSourceFolder)
340+
val file = VfsUtil.findRelativeFile(message.filePath, session.context.selectedRoot)
340341
// Wait for the file to be created and/or updated to the new content:
341342
if (file != null && file.content() == filePaths.find { it.zipFilePath == fileToUpdate }?.fileContent) {
342343
// Open a diff, showing the changes have been applied and the file now has identical left/right state:
@@ -729,7 +730,7 @@ class FeatureDevController(
729730

730731
val codeWhispererSettings = CodeWhispererSettings.getInstance().getAutoBuildSetting()
731732
val hasDevFile = session.context.checkForDevFile()
732-
val isPromptedForAutoBuildFeature = codeWhispererSettings.containsKey(session.context.getWorkspaceRoot())
733+
val isPromptedForAutoBuildFeature = codeWhispererSettings.containsKey(session.context.workspaceRoot.pathString)
733734

734735
if (hasDevFile && !isPromptedForAutoBuildFeature) {
735736
promptAllowQCommandsConsent(messenger, tabId)
@@ -812,8 +813,8 @@ class FeatureDevController(
812813

813814
private suspend fun modifyDefaultSourceFolder(tabId: String) {
814815
val session = getSessionInfo(tabId)
815-
val currentSourceFolder = session.context.selectedSourceFolder
816-
val projectRoot = session.context.projectRoot
816+
val currentSourceFolder = session.context.selectedRoot
817+
val workspaceRoot = session.context.workspaceRoot
817818

818819
val modifyFolderFollowUp = FollowUp(
819820
pillText = message("amazonqFeatureDev.follow_up.modify_source_folder"),
@@ -840,7 +841,7 @@ class FeatureDevController(
840841
}
841842

842843
// The folder is not in the workspace
843-
if (!selectedFolder.path.startsWith(projectRoot.path)) {
844+
if (!selectedFolder.path.startsWith(workspaceRoot.pathString)) {
844845
logger.info { "Selected folder not in workspace: ${selectedFolder.path}" }
845846

846847
messenger.sendAnswer(
@@ -860,7 +861,7 @@ class FeatureDevController(
860861

861862
logger.info { "Selected correct folder inside workspace: ${selectedFolder.path}" }
862863

863-
session.context.selectedSourceFolder = selectedFolder
864+
session.context.selectedRoot = selectedFolder
864865
result = Result.Succeeded
865866

866867
messenger.sendAnswer(

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/CodeGenerationState.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ class CodeGenerationState(
9696
var insertedCharacters = 0
9797
codeGenerationResult.newFiles.forEach { file ->
9898
// FIXME: Ideally, the before content should be read from the uploaded context instead of from disk, to avoid drift
99-
val before = config.repoContext.selectedSourceFolder
99+
val before = config.repoContext.selectedRoot
100100
.toNioPath()
101101
.resolve(file.zipFilePath)
102102
.toFile()

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/PrepareCodeGenerationState.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import software.aws.toolkits.telemetry.AmazonqTelemetry
1919
import software.aws.toolkits.telemetry.AmazonqUploadIntent
2020
import software.aws.toolkits.telemetry.Result
2121
import java.util.UUID
22+
import kotlin.io.path.pathString
2223

2324
private val logger = getLogger<PrepareCodeGenerationState>()
2425

@@ -49,7 +50,7 @@ class PrepareCodeGenerationState(
4950
messenger.sendAnswerPart(tabId = this.tabID, message = message("amazonqFeatureDev.chat_message.uploading_code"))
5051
messenger.sendUpdatePlaceholder(tabId = this.tabID, newPlaceholder = message("amazonqFeatureDev.chat_message.uploading_code"))
5152

52-
val isAutoBuildFeatureEnabled = CodeWhispererSettings.getInstance().isAutoBuildFeatureEnabled(this.config.repoContext.getWorkspaceRoot())
53+
val isAutoBuildFeatureEnabled = CodeWhispererSettings.getInstance().isAutoBuildFeatureEnabled(this.config.repoContext.workspaceRoot.pathString)
5354
val repoZipResult = config.repoContext.getProjectZip(isAutoBuildFeatureEnabled = isAutoBuildFeatureEnabled)
5455
val zipFileChecksum = repoZipResult.checksum
5556
zipFileLength = repoZipResult.contentLength

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/Session.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import com.intellij.openapi.project.Project
88
import com.intellij.openapi.vfs.VfsUtil
99
import software.aws.toolkits.jetbrains.common.util.resolveAndCreateOrUpdateFile
1010
import software.aws.toolkits.jetbrains.common.util.resolveAndDeleteFile
11-
import software.aws.toolkits.jetbrains.services.amazonq.FeatureDevSessionContext
1211
import software.aws.toolkits.jetbrains.services.amazonq.messages.MessagePublisher
12+
import software.aws.toolkits.jetbrains.services.amazonq.project.FeatureDevSessionContext
1313
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.CODE_GENERATION_RETRY_LIMIT
1414
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ConversationIdNotFoundException
1515
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.FEATURE_NAME
@@ -130,7 +130,7 @@ class Session(val tabID: String, val project: Project) {
130130
) {
131131
val newFilePaths = filePaths.filter { !it.rejected && !it.changeApplied }
132132
val newDeletedFiles = deletedFiles.filter { !it.rejected && !it.changeApplied }
133-
val selectedSourceFolder = context.selectedSourceFolder.toNioPath()
133+
val selectedSourceFolder = context.selectedRoot.toNioPath()
134134

135135
runCatching {
136136
var insertedLines = 0
@@ -174,15 +174,15 @@ class Session(val tabID: String, val project: Project) {
174174
ReferenceLogController.addReferenceLog(references, project)
175175

176176
// Taken from https://intellij-support.jetbrains.com/hc/en-us/community/posts/206118439-Refresh-after-external-changes-to-project-structure-and-sources
177-
VfsUtil.markDirtyAndRefresh(true, true, true, context.selectedSourceFolder)
177+
VfsUtil.markDirtyAndRefresh(true, true, true, context.selectedRoot)
178178
}
179179

180180
// Suppressing because insertNewFiles needs to be a suspend function in order to be tested
181181
@Suppress("RedundantSuspendModifier")
182182
suspend fun insertNewFiles(
183183
filePaths: List<NewFileZipInfo>,
184184
) {
185-
val selectedSourceFolder = context.selectedSourceFolder.toNioPath()
185+
val selectedSourceFolder = context.selectedRoot.toNioPath()
186186

187187
filePaths.forEach {
188188
resolveAndCreateOrUpdateFile(selectedSourceFolder, it.zipFilePath, it.fileContent)
@@ -195,7 +195,7 @@ class Session(val tabID: String, val project: Project) {
195195
suspend fun applyDeleteFiles(
196196
deletedFiles: List<DeletedFileInfo>,
197197
) {
198-
val selectedSourceFolder = context.selectedSourceFolder.toNioPath()
198+
val selectedSourceFolder = context.selectedRoot.toNioPath()
199199

200200
deletedFiles.forEach {
201201
resolveAndDeleteFile(selectedSourceFolder, it.zipFilePath)

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/SessionStateTypes.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
package software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session
55

66
import com.fasterxml.jackson.annotation.JsonValue
7-
import software.aws.toolkits.jetbrains.services.amazonq.FeatureDevSessionContext
7+
import software.aws.toolkits.jetbrains.services.amazonq.project.FeatureDevSessionContext
88
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.CancellationTokenSource
99
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.FeatureDevService
1010
import software.aws.toolkits.jetbrains.services.cwc.messages.RecommendationContentSpan

0 commit comments

Comments
 (0)