Skip to content

Commit 8854f88

Browse files
author
C Tidd
committed
feat(amazonq): Add support for multi-project workspaces.
1 parent 246b317 commit 8854f88

File tree

21 files changed

+460
-467
lines changed

21 files changed

+460
-467
lines changed

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

+1-1
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

+7-7
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
@@ -308,7 +308,7 @@ class DocController(
308308
val session = getSessionInfo(tabId)
309309
val docGenerationTask = docGenerationTasks.getTask(tabId)
310310

311-
val currentSourceFolder = session.context.selectedSourceFolder
311+
val currentSourceFolder = session.context.selectedRoot
312312

313313
try {
314314
messenger.sendFolderConfirmationMessage(
@@ -405,7 +405,7 @@ class DocController(
405405
inMemoryFile.isWritable = false
406406
FileEditorManager.getInstance(context.project).openFile(inMemoryFile, true)
407407
} else {
408-
val existingFile = VfsUtil.findRelativeFile(message.filePath, session.context.selectedSourceFolder)
408+
val existingFile = VfsUtil.findRelativeFile(message.filePath, session.context.selectedRoot)
409409
val leftDiffContent = if (existingFile == null) {
410410
EmptyContent()
411411
} else {
@@ -956,8 +956,8 @@ class DocController(
956956

957957
private suspend fun modifyDefaultSourceFolder(tabId: String) {
958958
val session = getSessionInfo(tabId)
959-
val currentSourceFolder = session.context.selectedSourceFolder
960-
val projectRoot = session.context.projectRoot
959+
val currentSourceFolder = session.context.selectedRoot
960+
val workspaceRoot = session.context.workspaceRoot
961961
val docGenerationTask = docGenerationTasks.getTask(tabId)
962962

963963
withContext(EDT) {
@@ -1004,15 +1004,15 @@ class DocController(
10041004
return@withContext
10051005
}
10061006

1007-
if (selectedFolder.path == projectRoot.path) {
1007+
if (selectedFolder.path == workspaceRoot.toString()) {
10081008
docGenerationTask.folderLevel = DocFolderLevel.ENTIRE_WORKSPACE
10091009
} else {
10101010
docGenerationTask.folderLevel = DocFolderLevel.SUB_FOLDER
10111011
}
10121012

10131013
logger.info { "Selected correct folder inside workspace: ${selectedFolder.path}" }
10141014

1015-
session.context.selectedSourceFolder = selectedFolder
1015+
session.context.selectedRoot = selectedFolder
10161016

10171017
promptForDocTarget(tabId)
10181018

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

+6-6
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

+2-26
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,6 @@
44
package software.aws.toolkits.jetbrains.services.amazonqDoc.session
55

66
import com.intellij.openapi.project.Project
7-
import com.intellij.openapi.vfs.VirtualFile
8-
import software.aws.toolkits.jetbrains.services.amazonq.FeatureDevSessionContext
9-
import software.aws.toolkits.jetbrains.services.amazonqDoc.SUPPORTED_DIAGRAM_EXT_SET
10-
import software.aws.toolkits.jetbrains.services.amazonqDoc.SUPPORTED_DIAGRAM_FILE_NAME_SET
7+
import software.aws.toolkits.jetbrains.services.amazonq.project.FeatureDevSessionContext
118

12-
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-
}
33-
}
9+
class DocSessionContext(project: Project, maxProjectSizeBytes: Long? = null) : FeatureDevSessionContext(project, maxProjectSizeBytes)

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

+1-1
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

+8-8
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
@@ -249,7 +249,7 @@ class FeatureDevController(
249249
when (sessionState) {
250250
is PrepareCodeGenerationState -> {
251251
runInEdt {
252-
val existingFile = VfsUtil.findRelativeFile(message.filePath, session.context.selectedSourceFolder)
252+
val existingFile = VfsUtil.findRelativeFile(message.filePath, session.context.selectedRoot)
253253

254254
val leftDiffContent = if (existingFile == null) {
255255
EmptyContent()
@@ -336,7 +336,7 @@ class FeatureDevController(
336336
var pollAttempt = 0
337337
val pollDelayMs = 10L
338338
while (pollAttempt < 5) {
339-
val file = VfsUtil.findRelativeFile(message.filePath, session.context.selectedSourceFolder)
339+
val file = VfsUtil.findRelativeFile(message.filePath, session.context.selectedRoot)
340340
// Wait for the file to be created and/or updated to the new content:
341341
if (file != null && file.content() == filePaths.find { it.zipFilePath == fileToUpdate }?.fileContent) {
342342
// Open a diff, showing the changes have been applied and the file now has identical left/right state:
@@ -729,7 +729,7 @@ class FeatureDevController(
729729

730730
val codeWhispererSettings = CodeWhispererSettings.getInstance().getAutoBuildSetting()
731731
val hasDevFile = session.context.checkForDevFile()
732-
val isPromptedForAutoBuildFeature = codeWhispererSettings.containsKey(session.context.getWorkspaceRoot())
732+
val isPromptedForAutoBuildFeature = codeWhispererSettings.containsKey(session.context.workspaceRoot.path)
733733

734734
if (hasDevFile && !isPromptedForAutoBuildFeature) {
735735
promptAllowQCommandsConsent(messenger, tabId)
@@ -812,8 +812,8 @@ class FeatureDevController(
812812

813813
private suspend fun modifyDefaultSourceFolder(tabId: String) {
814814
val session = getSessionInfo(tabId)
815-
val currentSourceFolder = session.context.selectedSourceFolder
816-
val projectRoot = session.context.projectRoot
815+
val currentSourceFolder = session.context.selectedRoot
816+
val workspaceRoot = session.context.workspaceRoot
817817

818818
val modifyFolderFollowUp = FollowUp(
819819
pillText = message("amazonqFeatureDev.follow_up.modify_source_folder"),
@@ -840,7 +840,7 @@ class FeatureDevController(
840840
}
841841

842842
// The folder is not in the workspace
843-
if (!selectedFolder.path.startsWith(projectRoot.path)) {
843+
if (!selectedFolder.path.startsWith(workspaceRoot.path)) {
844844
logger.info { "Selected folder not in workspace: ${selectedFolder.path}" }
845845

846846
messenger.sendAnswer(
@@ -860,7 +860,7 @@ class FeatureDevController(
860860

861861
logger.info { "Selected correct folder inside workspace: ${selectedFolder.path}" }
862862

863-
session.context.selectedSourceFolder = selectedFolder
863+
session.context.selectedRoot = selectedFolder
864864
result = Result.Succeeded
865865

866866
messenger.sendAnswer(

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

+1-1
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

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class PrepareCodeGenerationState(
4949
messenger.sendAnswerPart(tabId = this.tabID, message = message("amazonqFeatureDev.chat_message.uploading_code"))
5050
messenger.sendUpdatePlaceholder(tabId = this.tabID, newPlaceholder = message("amazonqFeatureDev.chat_message.uploading_code"))
5151

52-
val isAutoBuildFeatureEnabled = CodeWhispererSettings.getInstance().isAutoBuildFeatureEnabled(this.config.repoContext.getWorkspaceRoot())
52+
val isAutoBuildFeatureEnabled = CodeWhispererSettings.getInstance().isAutoBuildFeatureEnabled(this.config.repoContext.workspaceRoot.toString())
5353
val repoZipResult = config.repoContext.getProjectZip(isAutoBuildFeatureEnabled = isAutoBuildFeatureEnabled)
5454
val zipFileChecksum = repoZipResult.checksum
5555
zipFileLength = repoZipResult.contentLength

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

+5-5
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

+1-1
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)