Skip to content

Commit 22a6527

Browse files
committed
Merge branch 'feature/q-lsp-chat' into rli/post-refactor
Conflicts: plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt
2 parents 04daaae + 20f1abc commit 22a6527

File tree

20 files changed

+928
-94
lines changed

20 files changed

+928
-94
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "bugfix",
3+
"description" : "Fix JavascriptLanguage not found on 2025.1+"
4+
}

plugins/amazonq/chat/jetbrains-community/resources/META-INF/plugin-chat.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
<projectListeners>
99
<listener class="software.aws.toolkits.jetbrains.services.amazonq.toolwindow.AmazonQToolWindowListener"
1010
topic="com.intellij.openapi.wm.ex.ToolWindowManagerListener"/>
11-
<listener class="software.aws.toolkits.jetbrains.services.amazonq.project.ProjectContextEditorListener"
12-
topic="com.intellij.openapi.fileEditor.FileEditorManagerListener"/>
1311
</projectListeners>
1412

1513
<extensions defaultExtensionNs="com.intellij">

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import com.intellij.openapi.project.Project
1010
import com.intellij.openapi.util.Disposer
1111
import com.intellij.ui.jcef.JBCefJSQuery
1212
import org.cef.CefApp
13+
import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService
1314
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
1415
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AwsServerCapabilitiesProvider
1516
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.FlareUiMessage
@@ -73,12 +74,6 @@ class Browser(parent: Disposable, private val webUri: URI, val project: Project)
7374
.executeJavaScript("window.postMessage($message)", jcefBrowser.cefBrowser.url, 0)
7475
}
7576

76-
// TODO: Remove this once chat has been integrated with agents
77-
fun post(message: String) =
78-
jcefBrowser
79-
.cefBrowser
80-
.executeJavaScript("window.postMessage(JSON.stringify($message))", jcefBrowser.cefBrowser.url, 0)
81-
8277
// Load the chat web app into the jcefBrowser
8378
private fun loadWebView(
8479
isCodeTransformAvailable: Boolean,
@@ -122,10 +117,11 @@ class Browser(parent: Disposable, private val webUri: URI, val project: Project)
122117
val postMessageToJavaJsCode = receiveMessageQuery.inject("JSON.stringify(message)")
123118
val connectorAdapterPath = "http://mynah/js/connectorAdapter.js"
124119
generateQuickActionConfig()
120+
// https://github.com/highlightjs/highlight.js/issues/1387
125121
// language=HTML
126122
val jsScripts = """
127-
<script type="text/javascript" src="$connectorAdapterPath"></script>
128-
<script type="text/javascript" src="$webUri" defer onload="init()"></script>
123+
<script type="text/javascript" charset="UTF-8" src="$connectorAdapterPath"></script>
124+
<script type="text/javascript" charset="UTF-8" src="$webUri" defer onload="init()"></script>
129125
130126
<script type="text/javascript">
131127
@@ -159,8 +155,7 @@ class Browser(parent: Disposable, private val webUri: URI, val project: Project)
159155
pairProgrammingAcknowledged: ${!MeetQSettings.getInstance().amazonQChatPairProgramming}
160156
},
161157
hybridChatConnector,
162-
{}
163-
158+
${CodeWhispererFeatureConfigService.getInstance().getFeatureConfigJsonString()}
164159
);
165160
}
166161
</script>

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import com.fasterxml.jackson.databind.JsonNode
77
import com.google.gson.Gson
88
import com.intellij.ide.BrowserUtil
99
import com.intellij.ide.util.RunOnceUtil
10+
import com.intellij.openapi.application.runInEdt
11+
import com.intellij.openapi.options.ShowSettingsUtil
1012
import com.intellij.openapi.project.Project
1113
import com.intellij.ui.jcef.JBCefJSQuery.Response
1214
import kotlinx.coroutines.CompletableDeferred
@@ -34,6 +36,8 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AwsServerC
3436
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.ChatCommunicationManager
3537
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.FlareUiMessage
3638
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.getTextDocumentIdentifier
39+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.AUTH_FOLLOW_UP_CLICKED
40+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.AuthFollowUpClickNotification
3741
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ButtonClickNotification
3842
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ButtonClickParams
3943
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ButtonClickResult
@@ -86,6 +90,9 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.Inser
8690
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LinkClickNotification
8791
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LinkClickParams
8892
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ListConversationsRequest
93+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_SETTINGS
94+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_WORKSPACE_SETTINGS_KEY
95+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OpenSettingsNotification
8996
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OpenTabResponse
9097
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.PROMPT_INPUT_OPTIONS_CHANGE
9198
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.PromptInputOptionChangeNotification
@@ -105,6 +112,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.util.command
105112
import software.aws.toolkits.jetbrains.services.amazonq.util.tabType
106113
import software.aws.toolkits.jetbrains.services.amazonq.webview.theme.AmazonQTheme
107114
import software.aws.toolkits.jetbrains.services.amazonq.webview.theme.ThemeBrowserAdapter
115+
import software.aws.toolkits.jetbrains.services.codewhisperer.settings.CodeWhispererConfigurable
108116
import software.aws.toolkits.jetbrains.settings.MeetQSettings
109117
import software.aws.toolkits.resources.AwsCoreBundle
110118
import software.aws.toolkits.telemetry.MetricResult
@@ -407,6 +415,13 @@ class BrowserConnector(
407415
}
408416
}
409417
}
418+
AUTH_FOLLOW_UP_CLICKED -> {
419+
val message = serializer.deserializeChatMessages<AuthFollowUpClickNotification>(node)
420+
chatCommunicationManager.handleAuthFollowUpClicked(
421+
project,
422+
message.params
423+
)
424+
}
410425
CHAT_COPY_CODE_TO_CLIPBOARD -> {
411426
handleChatNotification<CopyCodeToClipboardNotification, CopyCodeToClipboardParams>(node) { server, params ->
412427
server.copyCodeToClipboard(params)
@@ -476,6 +491,13 @@ class BrowserConnector(
476491
)
477492
browser.postChat(uiMessage)
478493
}
494+
OPEN_SETTINGS -> {
495+
val openSettingsNotification = serializer.deserializeChatMessages<OpenSettingsNotification>(node)
496+
if (openSettingsNotification.params.settingKey != OPEN_WORKSPACE_SETTINGS_KEY) return
497+
runInEdt {
498+
ShowSettingsUtil.getInstance().showSettingsDialog(browser.project, CodeWhispererConfigurable::class.java)
499+
}
500+
}
479501
}
480502
}
481503

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4+
@file:Suppress("BannedImports")
45
package software.aws.toolkits.jetbrains.services.amazonq
56

7+
import com.google.gson.Gson
68
import com.intellij.openapi.components.Service
79
import com.intellij.openapi.components.service
810
import com.intellij.openapi.project.Project
@@ -17,7 +19,6 @@ import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
1719
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager
1820
import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererCustomization
1921
import software.aws.toolkits.jetbrains.utils.isQExpired
20-
2122
@Service
2223
class CodeWhispererFeatureConfigService {
2324
private val featureConfigs = mutableMapOf<String, FeatureContext>()
@@ -82,6 +83,17 @@ class CodeWhispererFeatureConfigService {
8283

8384
fun getChatWSContext(): Boolean = getFeatureValueForKey(CHAT_WS_CONTEXT).stringValue() == "TREATMENT"
8485

86+
// convert into mynahUI parsable string
87+
// format: '[["key1", {"name":"Feature1","variation":"A","value":true}]]'
88+
fun getFeatureConfigJsonString(): String {
89+
val jsonString = featureConfigs.entries.map { (key, value) ->
90+
"[\"$key\",${Gson().toJson(value)}]"
91+
}
92+
return """
93+
'$jsonString'
94+
""".trimIndent()
95+
}
96+
8597
// Get the feature value for the given key.
8698
// In case of a misconfiguration, it will return a default feature value of Boolean false.
8799
private fun getFeatureValueForKey(name: String): FeatureValue =

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

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ package software.aws.toolkits.jetbrains.services.amazonq.lsp
55

66
import com.intellij.diff.DiffContentFactory
77
import com.intellij.diff.DiffManager
8+
import com.intellij.diff.DiffManagerEx
89
import com.intellij.diff.requests.SimpleDiffRequest
910
import com.intellij.notification.NotificationType
1011
import com.intellij.openapi.application.ApplicationManager
1112
import com.intellij.openapi.fileChooser.FileChooserFactory
1213
import com.intellij.openapi.fileChooser.FileSaverDescriptor
1314
import com.intellij.openapi.fileEditor.FileEditorManager
1415
import com.intellij.openapi.project.Project
16+
import com.intellij.openapi.vfs.LocalFileSystem
1517
import com.intellij.openapi.vfs.VirtualFileManager
1618
import migration.software.aws.toolkits.jetbrains.settings.AwsSettings
1719
import org.eclipse.lsp4j.ConfigurationParams
@@ -51,6 +53,7 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.customization.Code
5153
import software.aws.toolkits.jetbrains.settings.CodeWhispererSettings
5254
import software.aws.toolkits.resources.message
5355
import java.io.File
56+
import java.nio.file.Files
5457
import java.nio.file.Paths
5558
import java.util.UUID
5659
import java.util.concurrent.CompletableFuture
@@ -268,40 +271,69 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC
268271
return CompletableFuture.completedFuture(Unit)
269272
}
270273

274+
private fun File.toVirtualFile() = LocalFileSystem.getInstance().findFileByIoFile(this)
275+
271276
override fun openFileDiff(params: OpenFileDiffParams): CompletableFuture<Unit> =
272277
CompletableFuture.supplyAsync(
273278
{
279+
var tempPath: java.nio.file.Path? = null
274280
try {
275-
val contentFactory = DiffContentFactory.getInstance()
276281
val fileName = Paths.get(params.originalFileUri).fileName.toString()
282+
// Create a temporary virtual file for syntax highlighting
283+
val fileExtension = fileName.substringAfterLast('.', "")
284+
tempPath = Files.createTempFile(null, ".$fileExtension")
285+
val virtualFile = tempPath.toFile()
286+
.also { it.setReadOnly() }
287+
.toVirtualFile()
277288

278289
val originalContent = params.originalFileContent ?: run {
279-
val file = File(params.originalFileUri)
280-
if (file.exists()) file.readText() else ""
290+
val sourceFile = File(params.originalFileUri)
291+
if (sourceFile.exists()) sourceFile.readText() else ""
281292
}
293+
294+
val contentFactory = DiffContentFactory.getInstance()
295+
var isNewFile = false
282296
val (leftContent, rightContent) = when {
283297
params.isDeleted -> {
284-
// For deleted files, show original on left, empty on right
285-
contentFactory.create(originalContent) to
298+
contentFactory.create(project, originalContent, virtualFile) to
286299
contentFactory.createEmpty()
287300
}
288301
else -> {
289-
// For new or modified files
290302
val newContent = params.fileContent.orEmpty()
291-
contentFactory.create(originalContent) to
292-
contentFactory.create(newContent)
303+
isNewFile = newContent == originalContent
304+
when {
305+
isNewFile -> {
306+
contentFactory.createEmpty() to
307+
contentFactory.create(project, newContent, virtualFile)
308+
}
309+
else -> {
310+
contentFactory.create(project, originalContent, virtualFile) to
311+
contentFactory.create(project, newContent, virtualFile)
312+
}
313+
}
293314
}
294315
}
295316
val diffRequest = SimpleDiffRequest(
296317
"$fileName ${message("aws.q.lsp.client.diff_message")}",
297318
leftContent,
298319
rightContent,
299320
"Original",
300-
if (params.isDeleted) "Deleted" else "Modified"
321+
when {
322+
params.isDeleted -> "Deleted"
323+
isNewFile -> "Created"
324+
else -> "Modified"
325+
}
301326
)
302-
DiffManager.getInstance().showDiff(project, diffRequest)
327+
(DiffManager.getInstance() as DiffManagerEx).showDiffBuiltin(project, diffRequest)
303328
} catch (e: Exception) {
304329
LOG.warn { "Failed to open file diff: ${e.message}" }
330+
} finally {
331+
// Clean up the temporary file
332+
try {
333+
tempPath?.let { Files.deleteIfExists(it) }
334+
} catch (e: Exception) {
335+
LOG.warn { "Failed to delete temporary file: ${e.message}" }
336+
}
305337
}
306338
},
307339
ApplicationManager.getApplication()::invokeLater

0 commit comments

Comments
 (0)