diff --git a/jetbrains/src/main/kotlin/com/sourcegraph/cody/agent/.editorconfig b/jetbrains/src/main/kotlin/com/sourcegraph/cody/agent/.editorconfig new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/jetbrains/src/main/kotlin/com/sourcegraph/cody/agent/CodyAgent.kt b/jetbrains/src/main/kotlin/com/sourcegraph/cody/agent/CodyAgent.kt index 0cbc48707bd5..3cc39bf7fd44 100644 --- a/jetbrains/src/main/kotlin/com/sourcegraph/cody/agent/CodyAgent.kt +++ b/jetbrains/src/main/kotlin/com/sourcegraph/cody/agent/CodyAgent.kt @@ -157,7 +157,9 @@ private constructor( webviewMessages = ClientCapabilities.WebviewMessagesEnum.`String-encoded`, accountSwitchingInWebview = - ClientCapabilities.AccountSwitchingInWebviewEnum.Enabled))) + ClientCapabilities.AccountSwitchingInWebviewEnum.Enabled, + showWindowMessage = + ClientCapabilities.ShowWindowMessageEnum.Request))) .thenApply { info -> logger.warn("Connected to Cody agent " + info.name) server.initialized(null) diff --git a/jetbrains/src/main/kotlin/com/sourcegraph/cody/agent/CodyAgentClient.kt b/jetbrains/src/main/kotlin/com/sourcegraph/cody/agent/CodyAgentClient.kt index b06d7db54842..cfc2c937a2c8 100644 --- a/jetbrains/src/main/kotlin/com/sourcegraph/cody/agent/CodyAgentClient.kt +++ b/jetbrains/src/main/kotlin/com/sourcegraph/cody/agent/CodyAgentClient.kt @@ -1,5 +1,8 @@ package com.sourcegraph.cody.agent +import com.intellij.notification.Notification +import com.intellij.notification.NotificationType +import com.intellij.notification.Notifications import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.runInEdt import com.intellij.openapi.diagnostic.Logger @@ -21,6 +24,7 @@ import com.sourcegraph.cody.agent.protocol_generated.SaveDialogOptionsParams import com.sourcegraph.cody.agent.protocol_generated.Secrets_DeleteParams import com.sourcegraph.cody.agent.protocol_generated.Secrets_GetParams import com.sourcegraph.cody.agent.protocol_generated.Secrets_StoreParams +import com.sourcegraph.cody.agent.protocol_generated.ShowWindowMessageParams import com.sourcegraph.cody.agent.protocol_generated.TextDocumentEditParams import com.sourcegraph.cody.agent.protocol_generated.TextDocument_ShowParams import com.sourcegraph.cody.agent.protocol_generated.UntitledTextDocument @@ -36,6 +40,8 @@ import com.sourcegraph.cody.statusbar.CodyStatus import com.sourcegraph.cody.statusbar.CodyStatusService import com.sourcegraph.cody.ui.web.NativeWebviewProvider import com.sourcegraph.common.BrowserOpener +import com.sourcegraph.common.NotificationGroups +import com.sourcegraph.common.ui.SimpleDumbAwareEDTAction import com.sourcegraph.utils.CodyEditorUtil import java.nio.file.Paths import java.util.concurrent.CompletableFuture @@ -152,6 +158,85 @@ class CodyAgentClient(private val project: Project, private val webview: NativeW return CompletableFuture.completedFuture(null) } + @JsonRequest("window/showSaveDialog") + fun window_showSaveDialog(params: SaveDialogOptionsParams): CompletableFuture { + // Let's use the first possible extension as default. + val ext = params.filters?.firstOrNull()?.value?.firstOrNull() ?: "" + var fileName = "Untitled.$ext".removeSuffix(".") + var outputDir: VirtualFile? = + if (params.defaultUri != null) { + val defaultUriPath = Paths.get(params.defaultUri) + fileName = defaultUriPath.fileName.toString() + VfsUtil.findFile(defaultUriPath.parent, true) + } else { + project.guessProjectDir() + } + + if (outputDir == null || !outputDir.exists()) { + outputDir = VfsUtil.getUserHomeDir() + } + + val title = params.title ?: "Cody: Save as New File" + val descriptor = FileSaverDescriptor(title, "Save file") + + val saveFileFuture = CompletableFuture() + runInEdt { + val dialog = FileChooserFactory.getInstance().createSaveFileDialog(descriptor, project) + val result = dialog.save(outputDir, fileName) + saveFileFuture.complete(result?.file?.path) + } + + return saveFileFuture + } + + @JsonNotification("window/didChangeContext") + fun window_didChangeContext(params: Window_DidChangeContextParams) { + if (params.key == "cody.activated") { + CodyAccount.setActivated(params.value?.toBoolean() ?: false) + CodyStatusService.notifyApplication(project, CodyStatus.CodyNotSignedIn) + } + if (params.key == "cody.serverEndpoint") { + val endpoint = params.value ?: return + CodyAccount.setActiveAccount(CodyAccount(SourcegraphServerPath(endpoint))) + CodyStatusService.resetApplication(project) + } + } + + @JsonRequest("window/showMessage") + fun window_showMessage(params: ShowWindowMessageParams): CompletableFuture { + val severity = + when (params.severity) { + ShowWindowMessageParams.SeverityEnum.Error -> NotificationType.ERROR + ShowWindowMessageParams.SeverityEnum.Warning -> NotificationType.WARNING + ShowWindowMessageParams.SeverityEnum.Information -> NotificationType.INFORMATION + } + val notification = + if (params.options?.detail != null) + Notification( + NotificationGroups.SOURCEGRAPH_ERRORS, + params.message, + params.options.detail, + severity) + else { + Notification(NotificationGroups.SOURCEGRAPH_ERRORS, params.message, severity) + } + + val selectedItem: CompletableFuture = CompletableFuture() + params.items?.map { item -> + notification.addAction(SimpleDumbAwareEDTAction(item) { selectedItem.complete(item) }) + } + notification.addAction( + SimpleDumbAwareEDTAction("Dismiss") { + notification.expire() + selectedItem.complete(null) + }) + + Notifications.Bus.notify(notification) + notification.notify(project) + + return selectedItem + } + // ============= // Notifications // ============= @@ -224,48 +309,4 @@ class CodyAgentClient(private val project: Project, private val webview: NativeW // TODO: Implement this. println("TODO, implement webview/dispose") } - - @JsonRequest("window/showSaveDialog") - fun window_showSaveDialog(params: SaveDialogOptionsParams): CompletableFuture { - // Let's use the first possible extension as default. - val ext = params.filters?.firstOrNull()?.value?.firstOrNull() ?: "" - var fileName = "Untitled.$ext".removeSuffix(".") - var outputDir: VirtualFile? = - if (params.defaultUri != null) { - val defaultUriPath = Paths.get(params.defaultUri) - fileName = defaultUriPath.fileName.toString() - VfsUtil.findFile(defaultUriPath.parent, true) - } else { - project.guessProjectDir() - } - - if (outputDir == null || !outputDir.exists()) { - outputDir = VfsUtil.getUserHomeDir() - } - - val title = params.title ?: "Cody: Save as New File" - val descriptor = FileSaverDescriptor(title, "Save file") - - val saveFileFuture = CompletableFuture() - runInEdt { - val dialog = FileChooserFactory.getInstance().createSaveFileDialog(descriptor, project) - val result = dialog.save(outputDir, fileName) - saveFileFuture.complete(result?.file?.path) - } - - return saveFileFuture - } - - @JsonNotification("window/didChangeContext") - fun window_didChangeContext(params: Window_DidChangeContextParams) { - if (params.key == "cody.activated") { - CodyAccount.setActivated(params.value?.toBoolean() ?: false) - CodyStatusService.notifyApplication(project, CodyStatus.CodyNotSignedIn) - } - if (params.key == "cody.serverEndpoint") { - val endpoint = params.value ?: return - CodyAccount.setActiveAccount(CodyAccount(SourcegraphServerPath(endpoint))) - CodyStatusService.resetApplication(project) - } - } }