getLanguageId();
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/cody/agent/ConfigFeaturesObserver.java:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.agent;
2 |
3 | /**
4 | * {@link ConfigFeaturesObserver} can be notified of changes in {@link ConfigFeatures} from the
5 | * agent.
6 | *
7 | * This can be attached to {@link CurrentConfigFeatures}, which multiplexes notifications from
8 | * {@link CodyAgentClient#onConfigFeatures}.
9 | */
10 | @FunctionalInterface
11 | public interface ConfigFeaturesObserver {
12 | void update(ConfigFeatures newConfigFeatures);
13 | }
14 |
--------------------------------------------------------------------------------
/src/integrationTest/resources/testProjects/documentCode/src/main/java/Foo.java:
--------------------------------------------------------------------------------
1 | import java.util.*;
2 |
3 | public class Foo {
4 |
5 | public void foo() {
6 | List mystery = new ArrayList<>();
7 | mystery.add(0);
8 | mystery.add(1);
9 | [[caret]]for (int i = 2; i < 10; i++) {
10 | mystery.add(mystery.get(i - 1) + mystery.get(i - 2));
11 | }
12 |
13 | for (int i = 0; i < 10; i++) {
14 | System.out.println(mystery.get(i));
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/chat/OpenChatAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.chat
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent
4 | import com.sourcegraph.cody.CodyToolWindowContent
5 | import com.sourcegraph.common.ui.DumbAwareEDTAction
6 |
7 | class OpenChatAction : DumbAwareEDTAction() {
8 |
9 | override fun actionPerformed(event: AnActionEvent) {
10 | val project = event.project ?: return
11 | CodyToolWindowContent.show(project)
12 | TODO("NYI, focus the chat thru TypeScript")
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/integrationTest/kotlin/com/sourcegraph/cody/util/CustomJunitClassRunner.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.util
2 |
3 | import org.junit.runners.BlockJUnit4ClassRunner
4 | import org.junit.runners.model.FrameworkMethod
5 |
6 | class CustomJunitClassRunner(klass: Class<*>?) : BlockJUnit4ClassRunner(klass) {
7 |
8 | private val repeatTimes: UInt? = System.getProperty("repeatTests")?.toUIntOrNull()
9 |
10 | override fun isIgnored(child: FrameworkMethod?): Boolean {
11 | return repeatTimes == null && super.isIgnored(child)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/config/notification/CodySettingChangeActionNotifier.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.config.notification
2 |
3 | import com.intellij.util.messages.Topic
4 |
5 | interface CodySettingChangeActionNotifier {
6 | companion object {
7 | @JvmStatic
8 | val TOPIC =
9 | Topic.create(
10 | "Sourcegraph Cody + Code Search: Cody settings have changed",
11 | CodySettingChangeActionNotifier::class.java)
12 | }
13 |
14 | fun afterAction(context: CodySettingChangeContext)
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/lenses/actions/EditUndoAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit.lenses.actions
2 |
3 | import com.sourcegraph.cody.agent.CodyAgentService
4 | import com.sourcegraph.cody.agent.protocol_generated.EditTask_UndoParams
5 |
6 | class EditUndoAction :
7 | LensEditAction({ project, _, _, taskId ->
8 | CodyAgentService.withAgent(project) { it.server.editTask_undo(EditTask_UndoParams(taskId)) }
9 | }) {
10 | companion object {
11 | const val ID = "cody.fixup.codelens.undo"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/scripts/version-from-git-tag.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -eu
3 | VERSION="$(git describe --tags | sed 's/^v//' | sed 's/-nightly//' | sed 's/-experimental//')"
4 | if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
5 | echo "Version $VERSION does not match semver pattern MAJOR.MINOR.PATCH where each part is a number"
6 | echo "To fix this problem, make sure you are running this script with a non-dirty work tree and that HEAD points to a commit that has an associated git tag using the format vMAJOR.MINOR.PATCH"
7 | exit 1
8 | fi
9 | echo $VERSION
10 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/lenses/EditCodeVisionGroupSettingProvider.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit.lenses
2 |
3 | import com.intellij.codeInsight.codeVision.settings.CodeVisionGroupSettingProvider
4 |
5 | class EditCodeVisionGroupSettingProvider : CodeVisionGroupSettingProvider {
6 | override val groupId: String = "EditCodeVisionProvider"
7 |
8 | override val groupName: String = "Cody Edit Lenses"
9 |
10 | override val description: String =
11 | "Lenses used by Cody for displaying control actions for the given edit"
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/CodyActionPrompter.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit
2 |
3 | import com.intellij.openapi.actionSystem.ActionPromoter
4 | import com.intellij.openapi.actionSystem.AnAction
5 | import com.intellij.openapi.actionSystem.DataContext
6 |
7 | internal class CodyActionPromoter : ActionPromoter {
8 | override fun promote(actions: List, context: DataContext): List {
9 | val (promoted, unknown) = actions.partition { it is InlineEditPromptEditCodeAction }
10 | return promoted + unknown
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/statusbar/ReportCodyBugAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.statusbar
2 |
3 | import com.intellij.ide.BrowserUtil
4 | import com.intellij.openapi.actionSystem.AnActionEvent
5 | import com.sourcegraph.cody.error.CodyErrorSubmitter
6 | import com.sourcegraph.common.ui.DumbAwareEDTAction
7 |
8 | class ReportCodyBugAction : DumbAwareEDTAction("Open GitHub To Report Cody Issue") {
9 | override fun actionPerformed(event: AnActionEvent) {
10 | BrowserUtil.open(CodyErrorSubmitter().getEncodedUrl(event.project))
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/agent/protocol/ErrorCode.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.agent.protocol
2 |
3 | import org.eclipse.lsp4j.jsonrpc.ResponseErrorException
4 |
5 | enum class ErrorCode(val code: Int) {
6 | ParseError(-32700),
7 | InvalidRequest(-32600),
8 | MethodNotFound(-32601),
9 | InvalidParams(-32602),
10 | InternalError(-32603),
11 | RateLimitError(-32000)
12 | }
13 |
14 | object ErrorCodeUtils {
15 | fun ResponseErrorException.toErrorCode(): ErrorCode? =
16 | ErrorCode.values().find { it.code == responseError.code }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/resources/icons/chat/llm/anthropic.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/lenses/actions/EditAcceptAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit.lenses.actions
2 |
3 | import com.sourcegraph.cody.agent.CodyAgentService
4 | import com.sourcegraph.cody.agent.protocol_generated.EditTask_AcceptParams
5 |
6 | class EditAcceptAction :
7 | LensEditAction({ project, _, _, taskId ->
8 | CodyAgentService.withAgent(project) {
9 | it.server.editTask_accept(EditTask_AcceptParams(taskId))
10 | }
11 | }) {
12 | companion object {
13 | const val ID = "cody.fixup.codelens.accept"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/lenses/actions/EditCancelAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit.lenses.actions
2 |
3 | import com.sourcegraph.cody.agent.CodyAgentService
4 | import com.sourcegraph.cody.agent.protocol_generated.EditTask_CancelParams
5 |
6 | class EditCancelAction :
7 | LensEditAction({ project, _, _, taskId ->
8 | CodyAgentService.withAgent(project) {
9 | it.server.editTask_cancel(EditTask_CancelParams(taskId))
10 | }
11 | }) {
12 | companion object {
13 | const val ID = "cody.fixup.codelens.cancel"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/resources/icons/edit/error.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/api/SourcegraphApiResponse.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.api
2 |
3 | import com.intellij.util.ThrowableConvertor
4 | import java.io.IOException
5 | import java.io.InputStream
6 | import java.io.Reader
7 |
8 | interface SourcegraphApiResponse {
9 | fun findHeader(headerName: String): String?
10 |
11 | @Throws(IOException::class)
12 | fun readBody(converter: ThrowableConvertor): T
13 |
14 | @Throws(IOException::class)
15 | fun handleBody(converter: ThrowableConvertor): T
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/autocomplete/action/DisposeInlaysActionHandler.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.autocomplete.action
2 |
3 | import com.intellij.openapi.actionSystem.DataContext
4 | import com.intellij.openapi.editor.Caret
5 | import com.intellij.openapi.editor.Editor
6 | import com.sourcegraph.cody.autocomplete.CodyAutocompleteManager
7 |
8 | class DisposeInlaysActionHandler : AutocompleteActionHandler() {
9 | override fun doExecute(editor: Editor, caret: Caret?, dataContext: DataContext?) =
10 | CodyAutocompleteManager.instance.disposeInlays(editor)
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/statusbar/CodyOpenSettingsAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.statusbar
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent
4 | import com.intellij.openapi.options.ShowSettingsUtil
5 | import com.sourcegraph.cody.config.ui.CodyConfigurable
6 | import com.sourcegraph.common.ui.DumbAwareEDTAction
7 |
8 | class CodyOpenSettingsAction : DumbAwareEDTAction("Open Settings") {
9 | override fun actionPerformed(e: AnActionEvent) {
10 | ShowSettingsUtil.getInstance().showSettingsDialog(e.project, CodyConfigurable::class.java)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/find/browser/HttpSchemeHandlerFactory.java:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.find.browser;
2 |
3 | import org.cef.browser.CefBrowser;
4 | import org.cef.browser.CefFrame;
5 | import org.cef.callback.CefSchemeHandlerFactory;
6 | import org.cef.handler.CefResourceHandler;
7 | import org.cef.network.CefRequest;
8 |
9 | public class HttpSchemeHandlerFactory implements CefSchemeHandlerFactory {
10 | @Override
11 | public CefResourceHandler create(
12 | CefBrowser browser, CefFrame frame, String schemeName, CefRequest request) {
13 | return new HttpSchemeHandler();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/history/state/EnhancedContextState.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.history.state
2 |
3 | import com.intellij.openapi.components.BaseState
4 | import com.intellij.util.xmlb.annotations.OptionTag
5 | import com.intellij.util.xmlb.annotations.Tag
6 |
7 | @Tag("enhancedContext")
8 | class EnhancedContextState : BaseState() {
9 | @get:OptionTag(tag = "isEnabled", nameAttribute = "") var isEnabled: Boolean by property(true)
10 |
11 | @get:OptionTag(tag = "remoteRepositories", nameAttribute = "")
12 | var remoteRepositories: MutableList by list()
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/config/ui/UpdateChannel.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.config.ui
2 |
3 | import com.intellij.util.ui.PresentableEnum
4 |
5 | enum class UpdateChannel(val channelUrl: String?) : PresentableEnum {
6 | Stable(null as String?),
7 | Nightly("https://plugins.jetbrains.com/plugins/nightly/9682"),
8 | Experimental("https://plugins.jetbrains.com/plugins/experimental/9682");
9 |
10 | override fun getPresentableText(): String {
11 | return when (this) {
12 | Stable -> "Stable"
13 | Nightly -> "Nightly"
14 | Experimental -> "Experimental"
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/sourcegraph/cody/autocomplete/render/InlayModelUtilTest.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.autocomplete.render
2 |
3 | import com.intellij.openapi.editor.impl.ImaginaryEditor
4 | import com.intellij.testFramework.fixtures.BasePlatformTestCase
5 |
6 | class InlayModelUtilTest : BasePlatformTestCase() {
7 | fun `test getAllInlaysForEditor`() {
8 | myFixture.configureByText("test.txt", "test")
9 | val imaginaryEditor = ImaginaryEditor(myFixture.project, myFixture.editor.document)
10 | val inlays = InlayModelUtil.getAllInlaysForEditor(imaginaryEditor)
11 | assertEquals(0, inlays.size)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/scripts/copy-protocol.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -eu
3 |
4 | echo "====================================================="
5 | echo "= Copying protocol files from CODY_DIR ="
6 | echo "====================================================="
7 |
8 | # if CODY_DIR is not set then we assume it's relative to the gitroot (look that up)
9 | # and then ../cody/ (which will need to be converted into an absolute path)
10 | if [ -z "${CODY_DIR:-}" ]; then
11 | CODY_DIR="$(git rev-parse --show-toplevel)/../cody/"
12 | echo "CODY_DIR is not set so using ${CODY_DIR}"
13 | fi
14 | CODY_DIR="$CODY_DIR" ./gradlew copyProtocol -PforceProtocolCopy=true
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/history/state/RemoteRepositoryState.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.history.state
2 |
3 | import com.intellij.openapi.components.BaseState
4 | import com.intellij.util.xmlb.annotations.OptionTag
5 | import com.intellij.util.xmlb.annotations.Tag
6 |
7 | @Tag("remoteRepository")
8 | class RemoteRepositoryState : BaseState() {
9 |
10 | @get:OptionTag(tag = "isEnabled", nameAttribute = "") var isEnabled: Boolean by property(true)
11 |
12 | @get:OptionTag(tag = "remoteUrl", nameAttribute = "") var remoteUrl: String? by string()
13 |
14 | @get:OptionTag(tag = "codebaseName", nameAttribute = "") var codebaseName: String? by string()
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/lenses/providers/EditDiffCodeVisionProvider.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit.lenses.providers
2 |
3 | import com.intellij.codeInsight.codeVision.CodeVisionRelativeOrdering
4 | import com.sourcegraph.cody.edit.lenses.EditCodeVisionProvider
5 | import com.sourcegraph.cody.edit.lenses.EditCodeVisionProviderMetadata
6 |
7 | class EditDiffCodeVisionProvider : EditCodeVisionProvider(EditDiffCodeVisionProvider) {
8 | companion object : EditCodeVisionProviderMetadata() {
9 | override val ordering: CodeVisionRelativeOrdering = showAfter(EditUndoCodeVisionProvider)
10 | override val command: String = "cody.fixup.codelens.diff"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/history/state/MessageState.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.history.state
2 |
3 | import com.intellij.openapi.components.BaseState
4 | import com.intellij.util.xmlb.annotations.OptionTag
5 | import com.intellij.util.xmlb.annotations.Tag
6 |
7 | @Tag("message")
8 | class MessageState : BaseState() {
9 |
10 | @get:OptionTag(tag = "text", nameAttribute = "") var text: String? by string()
11 |
12 | @get:OptionTag(tag = "speaker", nameAttribute = "")
13 | var speaker: SpeakerState? by enum()
14 |
15 | // todo var contextFiles by list()
16 |
17 | enum class SpeakerState {
18 | HUMAN,
19 | ASSISTANT
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/utils/ThreadingUtil.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.utils
2 |
3 | import com.intellij.openapi.application.ApplicationManager
4 | import java.util.concurrent.CompletableFuture
5 |
6 | object ThreadingUtil {
7 |
8 | fun runInEdtAndGet(task: () -> T): T {
9 | val app = ApplicationManager.getApplication()
10 | if (app.isDispatchThread) {
11 | return task()
12 | }
13 | val future = CompletableFuture()
14 | app.invokeLater {
15 | try {
16 | future.complete(task())
17 | } catch (exception: Exception) {
18 | future.completeExceptionally(exception)
19 | }
20 | }
21 | return future.get()
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/chat/actions/ExportChatsAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.chat.actions
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent
4 | import com.sourcegraph.cody.agent.CodyAgentService
5 | import com.sourcegraph.cody.agent.protocol_generated.ExecuteCommandParams
6 | import com.sourcegraph.common.ui.DumbAwareEDTAction
7 |
8 | class ExportChatsAction : DumbAwareEDTAction() {
9 |
10 | override fun actionPerformed(e: AnActionEvent) {
11 | val project = e.project ?: return
12 | CodyAgentService.withAgent(project) { agent ->
13 | agent.server.command_execute(ExecuteCommandParams("cody.chat.history.export", emptyList()))
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/find/OpenFindAction.java:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.find;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.project.DumbAware;
6 | import com.intellij.openapi.project.Project;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | public class OpenFindAction extends AnAction implements DumbAware {
10 | @Override
11 | public void actionPerformed(@NotNull AnActionEvent event) {
12 | Project project = event.getProject();
13 | if (project != null) {
14 | FindService service = project.getService(FindService.class);
15 | service.showPopup();
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/listeners/EditorChangesBus.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.listeners
2 |
3 | import com.intellij.openapi.project.Project
4 | import com.sourcegraph.cody.agent.protocol_generated.ProtocolTextDocument
5 |
6 | typealias EditorChangesListener = (project: Project?, textDocument: ProtocolTextDocument) -> Unit
7 |
8 | object EditorChangesBus {
9 | @Volatile var listeners: List = listOf()
10 |
11 | fun addListener(notify: EditorChangesListener) {
12 | listeners = listeners + notify
13 | }
14 |
15 | fun documentChanged(project: Project?, textDocument: ProtocolTextDocument) {
16 | listeners.forEach { it(project, textDocument) }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/lenses/providers/EditWorkingCodeVisionProvider.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit.lenses.providers
2 |
3 | import com.intellij.codeInsight.codeVision.CodeVisionRelativeOrdering
4 | import com.sourcegraph.cody.edit.lenses.EditCodeVisionProvider
5 | import com.sourcegraph.cody.edit.lenses.EditCodeVisionProviderMetadata
6 |
7 | class EditWorkingCodeVisionProvider : EditCodeVisionProvider(EditWorkingCodeVisionProvider) {
8 | companion object : EditCodeVisionProviderMetadata() {
9 | override val ordering: CodeVisionRelativeOrdering =
10 | CodeVisionRelativeOrdering.CodeVisionRelativeOrderingFirst
11 | override val command: String = "cody.chat.focus"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/lenses/providers/EditRetryCodeVisionProvider.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit.lenses.providers
2 |
3 | import com.intellij.codeInsight.codeVision.CodeVisionRelativeOrdering
4 | import com.sourcegraph.cody.edit.lenses.EditCodeVisionProvider
5 | import com.sourcegraph.cody.edit.lenses.EditCodeVisionProviderMetadata
6 |
7 | class EditRetryCodeVisionProvider : EditCodeVisionProvider(EditRetryCodeVisionProvider) {
8 | companion object : EditCodeVisionProviderMetadata() {
9 | override val ordering: CodeVisionRelativeOrdering =
10 | CodeVisionRelativeOrdering.CodeVisionRelativeOrderingLast
11 | override val command: String = "cody.fixup.codelens.retry"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/vcs/RevisionContext.java:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.vcs;
2 |
3 | import com.intellij.openapi.vfs.VirtualFile;
4 | import org.jetbrains.annotations.NotNull;
5 |
6 | public class RevisionContext {
7 | private final String revisionNumber; // Revision number or commit hash
8 | private final VirtualFile repoRoot;
9 |
10 | public RevisionContext(@NotNull String revisionNumber, @NotNull VirtualFile repoRoot) {
11 | this.revisionNumber = revisionNumber;
12 | this.repoRoot = repoRoot;
13 | }
14 |
15 | @NotNull
16 | public String getRevisionNumber() {
17 | return revisionNumber;
18 | }
19 |
20 | @NotNull
21 | public VirtualFile getRepoRoot() {
22 | return repoRoot;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/api/SourcegraphConfusingException.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.api
2 |
3 | import java.io.IOException
4 |
5 | open class SourcegraphConfusingException : IOException {
6 | private var myDetails: String? = null
7 |
8 | constructor(message: String?) : super(message)
9 |
10 | constructor(message: String?, cause: Throwable?) : super(message, cause)
11 |
12 | fun setDetails(details: String?) {
13 | myDetails = details
14 | }
15 |
16 | override val message: String?
17 | get() =
18 | if (myDetails == null) {
19 | super.message
20 | } else {
21 | """$myDetails
22 |
23 | ${super.message}"""
24 | .trimIndent()
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/intellij2023/kotlin/com/intellij/codeInsight/inline/completion/elements/InlineCompletionElement.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the
2 | // Apache 2.0 license.
3 | package com.intellij.codeInsight.inline.completion.elements
4 |
5 | /**
6 | * InlineCompletionElement is located in the following packages:
7 | * - 2023.2 - com.intellij.codeInsight.inline.completion
8 | * - 2023.3+ - com.intellij.codeInsight.inline.completion.elements
9 | *
10 | * We need that class in CodyInlineCompletionProvider::getSuggestion which is an API from 2023.3+ so
11 | * we need to provide our own stub to make compiler happy with IntelliJ platform 2023.2.
12 | */
13 | interface InlineCompletionElement
14 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/config/migration/AccountsMigration.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.config.migration
2 |
3 | import com.sourcegraph.cody.auth.CodyAccount
4 | import com.sourcegraph.cody.auth.deprecated.DeprecatedCodyAccountManager
5 |
6 | object AccountsMigration {
7 | fun migrate() {
8 | val codyAccountManager = DeprecatedCodyAccountManager.getInstance()
9 | codyAccountManager.getAccounts().forEach { oldAccount ->
10 | val token = codyAccountManager.getTokenForAccount(oldAccount)
11 | if (token != null) {
12 | CodyAccount(oldAccount.server).storeToken(token)
13 | }
14 | }
15 |
16 | codyAccountManager.account?.server?.let { CodyAccount.setActiveAccount(CodyAccount(it)) }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/config/notification/ChangeListener.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.config.notification
2 |
3 | import com.intellij.openapi.Disposable
4 | import com.intellij.openapi.diagnostic.Logger
5 | import com.intellij.openapi.project.Project
6 | import com.intellij.util.messages.MessageBusConnection
7 | import com.sourcegraph.find.browser.JavaToJSBridge
8 |
9 | abstract class ChangeListener(protected val project: Project) : Disposable {
10 | protected val connection: MessageBusConnection = project.messageBus.connect()
11 | var javaToJSBridge: JavaToJSBridge? = null
12 | protected val logger = Logger.getInstance(ChangeListener::class.java)
13 |
14 | override fun dispose() {
15 | connection.disconnect()
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/lenses/providers/EditUndoCodeVisionProvider.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit.lenses.providers
2 |
3 | import com.intellij.codeInsight.codeVision.CodeVisionRelativeOrdering
4 | import com.intellij.ui.JBColor
5 | import com.sourcegraph.cody.edit.lenses.EditCodeVisionProvider
6 | import com.sourcegraph.cody.edit.lenses.EditCodeVisionProviderMetadata
7 |
8 | class EditUndoCodeVisionProvider : EditCodeVisionProvider(EditUndoCodeVisionProvider) {
9 | companion object : EditCodeVisionProviderMetadata() {
10 | override val ordering: CodeVisionRelativeOrdering = showAfter(EditAcceptCodeVisionProvider)
11 | override val command: String = "cody.fixup.codelens.undo"
12 | override val textColor: JBColor = JBColor.RED
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/lenses/actions/EditRetryAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit.lenses.actions
2 |
3 | import com.intellij.openapi.application.runInEdt
4 | import com.sourcegraph.cody.edit.EditCommandPrompt
5 | import com.sourcegraph.cody.edit.actions.EditCodeAction
6 |
7 | class EditRetryAction :
8 | LensEditAction({ project, _, editor, taskId ->
9 | runInEdt {
10 | val completedFixup = EditCodeAction.completedEditTasks[taskId]
11 | if (completedFixup != null) {
12 | runInEdt {
13 | EditCommandPrompt(project, editor, "Edit instructions and Retry", completedFixup)
14 | }
15 | }
16 | }
17 | }) {
18 | companion object {
19 | const val ID = "cody.fixup.codelens.retry"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/lenses/providers/EditCancelCodeVisionProvider.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit.lenses.providers
2 |
3 | import com.intellij.codeInsight.codeVision.CodeVisionRelativeOrdering
4 | import com.intellij.ui.JBColor
5 | import com.sourcegraph.cody.edit.lenses.EditCodeVisionProvider
6 | import com.sourcegraph.cody.edit.lenses.EditCodeVisionProviderMetadata
7 |
8 | class EditCancelCodeVisionProvider : EditCodeVisionProvider(EditCancelCodeVisionProvider) {
9 | companion object : EditCodeVisionProviderMetadata() {
10 | override val ordering: CodeVisionRelativeOrdering = showAfter(EditWorkingCodeVisionProvider)
11 | override val command: String = "cody.fixup.codelens.cancel"
12 | override val textColor: JBColor = JBColor.RED
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/statusbar/CodyEnableAutocompleteAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.statusbar
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent
4 | import com.sourcegraph.cody.config.CodyApplicationSettings
5 | import com.sourcegraph.common.ui.DumbAwareEDTAction
6 | import com.sourcegraph.config.ConfigUtil
7 |
8 | class CodyEnableAutocompleteAction : DumbAwareEDTAction("Enable Cody Autocomplete") {
9 | override fun actionPerformed(e: AnActionEvent) {
10 | CodyApplicationSettings.instance.isCodyAutocompleteEnabled = true
11 | }
12 |
13 | override fun update(e: AnActionEvent) {
14 | super.update(e)
15 | e.presentation.isEnabledAndVisible =
16 | ConfigUtil.isCodyEnabled() && !ConfigUtil.isCodyAutocompleteEnabled()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/actions/BaseEditCodeActionHandler.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit.actions
2 |
3 | import com.intellij.openapi.actionSystem.DataContext
4 | import com.intellij.openapi.editor.Caret
5 | import com.intellij.openapi.editor.Editor
6 | import com.intellij.openapi.editor.actionSystem.EditorActionHandler
7 | import com.sourcegraph.utils.CodyEditorUtil
8 |
9 | open class BaseEditCodeActionHandler(val runAction: (Editor) -> Unit) : EditorActionHandler() {
10 | override fun isEnabledForCaret(editor: Editor, caret: Caret, dataContext: DataContext?): Boolean {
11 | return CodyEditorUtil.isEditorValidForAutocomplete(editor)
12 | }
13 |
14 | override fun doExecute(editor: Editor, where: Caret?, dataContext: DataContext?) {
15 | runAction(editor)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/statusbar/CodyWidgetFactory.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.statusbar
2 |
3 | import com.intellij.openapi.project.Project
4 | import com.intellij.openapi.util.Disposer
5 | import com.intellij.openapi.wm.StatusBarWidget
6 | import com.intellij.openapi.wm.impl.status.widget.StatusBarEditorBasedWidgetFactory
7 |
8 | class CodyWidgetFactory : StatusBarEditorBasedWidgetFactory() {
9 | override fun getId(): String = ID
10 |
11 | override fun getDisplayName(): String = "Cody"
12 |
13 | override fun createWidget(project: Project): StatusBarWidget = CodyStatusBarWidget(project)
14 |
15 | override fun disposeWidget(widget: StatusBarWidget) {
16 | Disposer.dispose(widget)
17 | }
18 |
19 | companion object {
20 | const val ID = "cody.statusBarWidget"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/utils/CodyLanguageUtil.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.utils
2 |
3 | import com.intellij.lang.Language
4 | import com.intellij.lang.LanguageUtil
5 | import com.intellij.openapi.editor.Document
6 | import com.intellij.openapi.fileEditor.FileDocumentManager
7 | import com.intellij.openapi.project.Project
8 | import com.sourcegraph.config.ConfigUtil
9 |
10 | object CodyLanguageUtil {
11 | @JvmStatic
12 | fun getLanguage(project: Project, document: Document): Language? {
13 | return LanguageUtil.getLanguageForPsi(
14 | project, FileDocumentManager.getInstance().getFile(document))
15 | }
16 |
17 | @JvmStatic
18 | fun isLanguageBlacklisted(language: Language): Boolean {
19 | return ConfigUtil.getBlacklistedAutocompleteLanguageIds().contains(language.id)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/lenses/providers/EditAcceptCodeVisionProvider.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit.lenses.providers
2 |
3 | import com.intellij.codeInsight.codeVision.CodeVisionRelativeOrdering
4 | import com.intellij.ui.JBColor
5 | import com.sourcegraph.cody.edit.lenses.EditCodeVisionProvider
6 | import com.sourcegraph.cody.edit.lenses.EditCodeVisionProviderMetadata
7 |
8 | class EditAcceptCodeVisionProvider : EditCodeVisionProvider(EditAcceptCodeVisionProvider) {
9 | companion object : EditCodeVisionProviderMetadata() {
10 | override val ordering: CodeVisionRelativeOrdering =
11 | CodeVisionRelativeOrdering.CodeVisionRelativeOrderingFirst
12 | override val command: String = "cody.fixup.codelens.accept"
13 | override val textColor: JBColor = JBColor.GREEN
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/history/state/AccountData.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.history.state
2 |
3 | import com.intellij.openapi.components.BaseState
4 | import com.intellij.util.xmlb.annotations.OptionTag
5 |
6 | class AccountData() : BaseState() {
7 | constructor(accountId: String) : this() {
8 | this.accountId = accountId
9 | }
10 |
11 | @get:OptionTag(tag = "accountId", nameAttribute = "") var accountId: String? by string()
12 |
13 | @get:OptionTag(tag = "chats", nameAttribute = "") var chats: MutableList by list()
14 |
15 | @get:OptionTag(tag = "defaultEnhancedContext", nameAttribute = "")
16 | var defaultEnhancedContext: EnhancedContextState? by property()
17 |
18 | @get:OptionTag(tag = "defaultLlm", nameAttribute = "") var defaultLlm: LLMState? by property()
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/config/notification/CodySettingChangeContext.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.config.notification
2 |
3 | class CodySettingChangeContext(
4 | val oldCodyEnabled: Boolean,
5 | val newCodyEnabled: Boolean,
6 | val oldCodyAutocompleteEnabled: Boolean,
7 | val newCodyAutocompleteEnabled: Boolean,
8 | val oldIsCustomAutocompleteColorEnabled: Boolean,
9 | val isCustomAutocompleteColorEnabled: Boolean,
10 | val oldCustomAutocompleteColor: Int?,
11 | val customAutocompleteColor: Int?,
12 | val oldBlacklistedAutocompleteLanguageIds: List,
13 | val newBlacklistedAutocompleteLanguageIds: List,
14 | val oldShouldAcceptNonTrustedCertificatesAutomatically: Boolean,
15 | val newShouldAcceptNonTrustedCertificatesAutomatically: Boolean
16 | )
17 |
--------------------------------------------------------------------------------
/src/main/resources/icons/chat/llm/google.svg:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/history/state/HistoryState.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.history.state
2 |
3 | import com.intellij.openapi.components.BaseState
4 | import com.intellij.util.xmlb.annotations.OptionTag
5 |
6 | class HistoryState : BaseState() {
7 |
8 | @get:OptionTag(tag = "accountData", nameAttribute = "")
9 | var accountData: MutableList by list()
10 |
11 | @Deprecated("")
12 | @get:OptionTag(tag = "chats", nameAttribute = "")
13 | var chats: MutableList by list()
14 |
15 | @Deprecated("")
16 | @get:OptionTag(tag = "defaultLlm", nameAttribute = "")
17 | var defaultLlm: LLMState? by property()
18 |
19 | @Deprecated("")
20 | @get:OptionTag(tag = "defaultEnhancedContext", nameAttribute = "")
21 | var defaultEnhancedContext: EnhancedContextState? by property()
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/resources/icons/repo-host-gitlab.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/agent/protocol_extensions/ModelUtil.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.agent.protocol_extensions
2 |
3 | import com.sourcegraph.cody.Icons
4 | import com.sourcegraph.cody.agent.protocol_generated.Model
5 | import javax.swing.Icon
6 |
7 | fun Model.getIcon(): Icon? =
8 | when (provider) {
9 | "Anthropic" -> Icons.LLM.Anthropic
10 | "OpenAI" -> Icons.LLM.OpenAI
11 | "Mistral" -> Icons.LLM.Mistral
12 | "Google" -> Icons.LLM.Google
13 | "Ollama" -> Icons.LLM.Ollama
14 | else -> null
15 | }
16 |
17 | fun Model.displayName(): String = buildString {
18 | append(title)
19 | append(" by $provider")
20 | }
21 |
22 | fun Model.isCodyProOnly(): Boolean = tags?.contains("pro") == true
23 |
24 | fun Model.isDeprecated(): Boolean = tags?.contains("deprecated") == true
25 |
--------------------------------------------------------------------------------
/src/main/resources/icons/repo-host-gitlab_dark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/icons/repo-host-generic.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/icons/repo-host-generic_dark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/icons/repo-host-github.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/internals/InternalsStatusBarActionGroup.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.internals
2 |
3 | import com.intellij.openapi.actionSystem.ActionUpdateThread
4 | import com.intellij.openapi.actionSystem.AnActionEvent
5 | import com.intellij.openapi.actionSystem.DefaultActionGroup
6 | import com.sourcegraph.config.ConfigUtil
7 |
8 | class InternalsStatusBarActionGroup : DefaultActionGroup() {
9 | override fun getActionUpdateThread(): ActionUpdateThread {
10 | return ActionUpdateThread.EDT
11 | }
12 |
13 | override fun update(e: AnActionEvent) {
14 | super.update(e)
15 | e.presentation.isVisible = ConfigUtil.isFeatureFlagEnabled("cody.feature.internals-menu")
16 | removeAll()
17 | if (e.project != null) {
18 | addAll(
19 | IgnoreOverrideAction(e.project!!),
20 | )
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/resources/icons/repo-host-github_dark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/config/SettingsModel.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.config
2 |
3 | import java.awt.Color
4 |
5 | data class SettingsModel(
6 | var defaultBranchName: String = "",
7 | var remoteUrlReplacements: String = "",
8 | var isCodyEnabled: Boolean = true,
9 | var isCodyAutocompleteEnabled: Boolean = true,
10 | var isCodyDebugEnabled: Boolean = false,
11 | var isCodyVerboseDebugEnabled: Boolean = false,
12 | var isCustomAutocompleteColorEnabled: Boolean = false,
13 | var customAutocompleteColor: Color? = null,
14 | var isLookupAutocompleteEnabled: Boolean = true,
15 | var isCodyUIHintsEnabled: Boolean = true,
16 | var blacklistedLanguageIds: List = listOf(),
17 | var shouldAcceptNonTrustedCertificatesAutomatically: Boolean = false,
18 | var shouldCheckForUpdates: Boolean = false
19 | )
20 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/config/actions/EnableOffScreenRenderingAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.config.actions
2 |
3 | import com.intellij.openapi.actionSystem.ActionUpdateThread
4 | import com.intellij.openapi.actionSystem.AnActionEvent
5 | import com.intellij.openapi.project.DumbAwareToggleAction
6 | import com.sourcegraph.cody.config.CodyApplicationSettings
7 |
8 | class EnableOffScreenRenderingAction : DumbAwareToggleAction() {
9 | override fun isSelected(e: AnActionEvent): Boolean {
10 | return CodyApplicationSettings.instance.isOffScreenRenderingEnabled
11 | }
12 |
13 | override fun setSelected(e: AnActionEvent, state: Boolean) {
14 | CodyApplicationSettings.instance.isOffScreenRenderingEnabled = state
15 | }
16 |
17 | override fun getActionUpdateThread(): ActionUpdateThread {
18 | return ActionUpdateThread.BGT
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/resources/icons/edit/edit_code.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/editor/CommandListener.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.editor
2 |
3 | import com.intellij.openapi.command.CommandEvent
4 | import com.intellij.openapi.command.CommandListener
5 | import com.intellij.openapi.project.Project
6 | import com.sourcegraph.cody.autocomplete.CodyAutocompleteManager
7 | import com.sourcegraph.utils.CodyEditorUtil
8 | import com.sourcegraph.utils.CodyEditorUtil.VIM_EXIT_INSERT_MODE_ACTION
9 |
10 | class CodyCommandListener(val project: Project) : CommandListener {
11 | override fun commandFinished(event: CommandEvent) {
12 | if (event.commandName.isNullOrBlank() ||
13 | event.commandName.equals(VIM_EXIT_INSERT_MODE_ACTION)) {
14 | CodyEditorUtil.getSelectedEditors(project).forEach { editor ->
15 | CodyAutocompleteManager.instance.disposeInlays(editor)
16 | }
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/chat/PromptHistory.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.chat
2 |
3 | open class PromptHistory(private val capacity: Int) {
4 | private val history = mutableListOf()
5 | private var currentIndex = 0
6 |
7 | fun add(item: String) {
8 | history.add(item)
9 | if (history.size > capacity) {
10 | history.removeAt(0)
11 | }
12 | resetHistory()
13 | }
14 |
15 | fun getPrevious(): String? {
16 | if (currentIndex > 0) {
17 | currentIndex--
18 | }
19 | return history.getOrNull(currentIndex)
20 | }
21 |
22 | fun getNext(): String? {
23 | if (currentIndex < history.size) {
24 | currentIndex++
25 | }
26 | return history.getOrNull(currentIndex)
27 | }
28 |
29 | fun isNotEmpty() = history.isNotEmpty()
30 |
31 | fun resetHistory() {
32 | currentIndex = history.size
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/agent/action/CodyAgentRestartAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.agent.action
2 |
3 | import com.intellij.notification.NotificationsManager
4 | import com.intellij.openapi.actionSystem.AnActionEvent
5 | import com.sourcegraph.cody.agent.CodyAgentService
6 | import com.sourcegraph.cody.agent.CodyConnectionTimeoutExceptionNotification
7 | import com.sourcegraph.common.ui.DumbAwareEDTAction
8 |
9 | class CodyAgentRestartAction : DumbAwareEDTAction("Restart Cody") {
10 | override fun actionPerformed(event: AnActionEvent) {
11 | event.project?.let { project ->
12 | CodyAgentService.getInstance(project).restartAgent(project)
13 | NotificationsManager.getNotificationsManager()
14 | .getNotificationsOfType(CodyConnectionTimeoutExceptionNotification::class.java, project)
15 | .forEach { it.expire() }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/.github/workflows/backport.yml:
--------------------------------------------------------------------------------
1 | name: Backport
2 | on:
3 | pull_request_target:
4 | types:
5 | - closed
6 | - labeled
7 |
8 | jobs:
9 | backport:
10 | name: Backport
11 | runs-on: ubuntu-latest
12 | # Only react to merged PRs for security reasons.
13 | # See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target.
14 | if: >
15 | github.event.pull_request.merged
16 | && (
17 | github.event.action == 'closed'
18 | || (
19 | github.event.action == 'labeled'
20 | && contains(github.event.label.name, 'backport')
21 | )
22 | )
23 | steps:
24 | - uses: sourcegraph/backport@v2
25 | with:
26 | github_token: ${{ secrets.BACKPORT_GITHUB_TOKEN }}
27 | label_pattern: '^backport (?jb-v\d+\.\d+\.x)$'
28 | team_reviews: ''
29 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/sourcegraph/cody/agent/protocol/extensions.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.agent.protocol
2 |
3 | import com.intellij.openapi.editor.Editor
4 | import com.sourcegraph.cody.agent.protocol_extensions.toOffsetRange
5 | import com.sourcegraph.cody.agent.protocol_generated.Range
6 | import junit.framework.TestCase
7 |
8 | fun Editor.testing_selectSubstring(substring: String) {
9 | val index = this.document.text.indexOf(substring)
10 | if (index == -1) {
11 | TestCase.fail("editor does not include substring '$substring'\n${this.document.text}")
12 | }
13 | this.selectionModel.setSelection(index, index + substring.length)
14 | TestCase.assertEquals(this.selectionModel.selectedText, substring)
15 | }
16 |
17 | fun Editor.testing_substring(range: Range): String {
18 | val (start, end) = range.toOffsetRange(document)
19 | return this.document.text.substring(start, end)
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/config/ui/lang/LanguageEntryColumn.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.config.ui.lang
2 |
3 | import com.intellij.util.ui.ColumnInfo
4 | import java.util.*
5 | import javax.swing.table.TableCellRenderer
6 |
7 | class LanguageEntryColumn(private val languageTable: AutocompleteLanguageTable) :
8 | ColumnInfo("Enabled Languages") {
9 | override fun getCustomizedRenderer(
10 | o: LanguageEntry?,
11 | renderer: TableCellRenderer?
12 | ): TableCellRenderer = LanguageNameCellRenderer(languageTable, o?.language?.displayName)
13 |
14 | override fun valueOf(languageEntry: LanguageEntry): String {
15 | return languageEntry.language.displayName
16 | }
17 |
18 | override fun getComparator(): Comparator? {
19 | return Comparator.comparing { le: LanguageEntry -> le.language.displayName.lowercase() }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/config/ui/lang/LanguageNameCellRenderer.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.config.ui.lang
2 |
3 | import com.intellij.ui.components.JBLabel
4 | import com.intellij.util.ui.JBUI
5 | import java.awt.Component
6 | import javax.swing.JTable
7 | import javax.swing.table.TableCellRenderer
8 |
9 | class LanguageNameCellRenderer(
10 | private val languageTable: AutocompleteLanguageTable,
11 | val displayName: String? = null
12 | ) : TableCellRenderer {
13 | override fun getTableCellRendererComponent(
14 | table: JTable?,
15 | value: Any?,
16 | isSelected: Boolean,
17 | hasFocus: Boolean,
18 | row: Int,
19 | column: Int
20 | ): Component {
21 | val label = JBLabel(displayName ?: value as? String ?: "")
22 | label.border = JBUI.Borders.empty(0, 8)
23 | label.isEnabled = languageTable.isEnabled
24 | return label
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/find/Search.java:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.find;
2 |
3 | public class Search {
4 | final String query;
5 | final boolean caseSensitive;
6 | final String patternType;
7 | final String selectedSearchContextSpec;
8 |
9 | public Search(
10 | String query, boolean caseSensitive, String patternType, String selectedSearchContextSpec) {
11 | this.query = query;
12 | this.caseSensitive = caseSensitive;
13 | this.patternType = patternType;
14 | this.selectedSearchContextSpec = selectedSearchContextSpec;
15 | }
16 |
17 | public String getQuery() {
18 | return query;
19 | }
20 |
21 | public boolean isCaseSensitive() {
22 | return caseSensitive;
23 | }
24 |
25 | public String getPatternType() {
26 | return patternType;
27 | }
28 |
29 | public String getSelectedSearchContextSpec() {
30 | return selectedSearchContextSpec;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/chat/actions/NewChatAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.chat.actions
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent
4 | import com.sourcegraph.cody.agent.CodyAgentService
5 | import com.sourcegraph.cody.auth.CodyAccount
6 | import com.sourcegraph.common.CodyBundle
7 | import com.sourcegraph.common.ui.DumbAwareEDTAction
8 |
9 | class NewChatAction : DumbAwareEDTAction() {
10 | override fun actionPerformed(event: AnActionEvent) {
11 | CodyAgentService.withAgent(event.project ?: return) { agent -> agent.server.chat_web_new(null) }
12 | }
13 |
14 | override fun update(event: AnActionEvent) {
15 | event.presentation.isEnabled = CodyAccount.hasActiveAccount()
16 | if (!event.presentation.isEnabled) {
17 | event.presentation.description =
18 | CodyBundle.getString("action.sourcegraph.disabled.description")
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/autocomplete/action/AcceptCodyAutocompleteAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.autocomplete.action
2 |
3 | import com.intellij.openapi.editor.actionSystem.EditorAction
4 | import java.util.concurrent.atomic.AtomicReference
5 |
6 | /**
7 | * The action that gets triggered when the user accepts a Cody completion.
8 | *
9 | * The action works by reading the Inlay at the caret position and inserting the completion text
10 | * into the editor.
11 | */
12 | object AcceptCodyAutocompleteAction : EditorAction(AcceptAutocompleteActionHandler()), CodyAction {
13 | // The tracker is used to keep track of the completion item that was accepted so that we can send
14 | // the completion-accepted notification AFTER we emit the document-change event. This is order
15 | // is expected by agent for certain telemetry events (not great, I know...).
16 | val tracker = AtomicReference()
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/actions/DocumentCodeAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit.actions
2 |
3 | import com.sourcegraph.cody.agent.CodyAgentService
4 | import com.sourcegraph.cody.agent.protocol_generated.Commands_CustomParams
5 | import com.sourcegraph.cody.agent.protocol_generated.CustomEditCommandResult
6 |
7 | class DocumentCodeAction :
8 | BaseEditCodeAction({ editor ->
9 | editor.project?.let { project ->
10 | CodyAgentService.withAgent(project) { agent ->
11 | val customCommandResult = agent.server.commands_custom(Commands_CustomParams("doc")).get()
12 | val result = customCommandResult as? CustomEditCommandResult ?: return@withAgent
13 | EditCodeAction.completedEditTasks[result.editResult.id] = result.editResult
14 | }
15 | }
16 | }) {
17 | companion object {
18 | const val ID: String = "cody.documentCodeAction"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/actions/TestCodeAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit.actions
2 |
3 | import com.sourcegraph.cody.agent.CodyAgentService
4 | import com.sourcegraph.cody.agent.protocol_generated.Commands_CustomParams
5 | import com.sourcegraph.cody.agent.protocol_generated.CustomEditCommandResult
6 |
7 | class TestCodeAction :
8 | BaseEditCodeAction({ editor ->
9 | editor.project?.let { project ->
10 | CodyAgentService.withAgent(project) { agent ->
11 | val customCommandResult =
12 | agent.server.commands_custom(Commands_CustomParams("test")).get()
13 | val result = customCommandResult as? CustomEditCommandResult ?: return@withAgent
14 | EditCodeAction.completedEditTasks[result.editResult.id] = result.editResult
15 | }
16 | }
17 | }) {
18 | companion object {
19 | const val ID: String = "cody.testCodeAction"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/integrationTest/kotlin/com/sourcegraph/cody/NonEdtIdeaTestExecutionPolicy.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody
2 |
3 | import com.intellij.testFramework.fixtures.IdeaTestExecutionPolicy
4 |
5 | /**
6 | * Used for all Cody JetBrains integration tests. You have to specify it via the System property
7 | * `idea.test.execution.policy` in order to run the tests.
8 | */
9 | @Suppress("unused")
10 | class NonEdtIdeaTestExecutionPolicy : IdeaTestExecutionPolicy() {
11 |
12 | override fun getName(): String = javaClass.name
13 |
14 | /**
15 | * This setting enables our integration tests. If they use the default policy and run on the EDT,
16 | * then they either deadlock or finish prematurely, because they cannot block on our long-running
17 | * multithreaded async backend operations. With this set to false, we run on the JUnit runner
18 | * thread, which can block.
19 | */
20 | override fun runInDispatchThread() = false
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/cody/CodyActionGroup.java:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody;
2 |
3 | import com.intellij.openapi.actionSystem.ActionUpdateThread;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.actionSystem.DefaultActionGroup;
6 | import com.sourcegraph.cody.auth.CodyAccount;
7 | import com.sourcegraph.config.ConfigUtil;
8 | import org.jetbrains.annotations.NotNull;
9 |
10 | public class CodyActionGroup extends DefaultActionGroup {
11 |
12 | @Override
13 | public @NotNull ActionUpdateThread getActionUpdateThread() {
14 | return ActionUpdateThread.EDT;
15 | }
16 |
17 | @Override
18 | public boolean isDumbAware() {
19 | return true;
20 | }
21 |
22 | @Override
23 | public void update(@NotNull AnActionEvent e) {
24 | super.update(e);
25 | e.getPresentation()
26 | .setVisible(ConfigUtil.isCodyEnabled() && CodyAccount.Companion.hasActiveAccount());
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/ui/web/WebPanelTabTitleProvider.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.ui.web
2 |
3 | import com.intellij.openapi.fileEditor.impl.EditorTabTitleProvider
4 | import com.intellij.openapi.project.DumbAware
5 | import com.intellij.openapi.project.Project
6 | import com.intellij.openapi.util.Key
7 | import com.intellij.openapi.vfs.VirtualFile
8 |
9 | /// Reads the title from the webview and presents it as the editor tab title.
10 | class WebPanelTabTitleProvider : EditorTabTitleProvider, DumbAware {
11 | companion object {
12 | val WEB_PANEL_TITLE_KEY = Key.create("WebViewTitle")
13 | }
14 |
15 | override fun getEditorTabTitle(project: Project, file: VirtualFile): String? {
16 | return file.getUserData(WEB_PANEL_TITLE_KEY) ?: ""
17 | }
18 |
19 | override fun getEditorTabTooltipText(project: Project, virtualFile: VirtualFile): String? {
20 | return getEditorTabTitle(project, virtualFile)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/cody/autocomplete/AutocompleteProviderType.java:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.autocomplete;
2 |
3 | import java.util.Arrays;
4 | import java.util.Optional;
5 | import org.jetbrains.annotations.NotNull;
6 |
7 | public enum AutocompleteProviderType {
8 | ANTHROPIC,
9 | FIREWORKS,
10 | EXPERIMENTAL_OLLAMA,
11 | EXPERIMENTAL_OPENAICOMPATIBLE,
12 | UNSTABLE_OPENAI;
13 |
14 | public static Optional optionalValueOf(@NotNull String name) {
15 | switch (name) {
16 | case "unstable-fireworks":
17 | return Optional.of(FIREWORKS);
18 | default:
19 | return Arrays.stream(AutocompleteProviderType.values())
20 | .filter(providerType -> providerType.vscodeSettingString().equals(name))
21 | .findFirst();
22 | }
23 | }
24 |
25 | public String vscodeSettingString() {
26 | return super.toString().toLowerCase().replace('_', '-');
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/InlineEditPromptEditCodeAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit
2 |
3 | import com.intellij.openapi.actionSystem.ActionUpdateThread
4 | import com.intellij.openapi.actionSystem.AnActionEvent
5 | import com.intellij.openapi.project.DumbAwareAction
6 | import com.sourcegraph.cody.edit.EditCommandPrompt.Companion.EDIT_COMMAND_PROMPT_KEY
7 |
8 | internal class InlineEditPromptEditCodeAction : DumbAwareAction() {
9 | private fun getInlineEditPrompt(event: AnActionEvent) = EDIT_COMMAND_PROMPT_KEY.get(event.project)
10 |
11 | override fun update(event: AnActionEvent) {
12 | event.presentation.isEnabledAndVisible = getInlineEditPrompt(event)?.isOkActionEnabled() == true
13 | }
14 |
15 | override fun actionPerformed(e: AnActionEvent) {
16 | getInlineEditPrompt(e)?.performOKAction()
17 | }
18 |
19 | override fun getActionUpdateThread(): ActionUpdateThread {
20 | return ActionUpdateThread.EDT
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/agent/CodyConnectionTimeoutExceptionNotification.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.agent
2 |
3 | import com.intellij.notification.Notification
4 | import com.intellij.notification.NotificationType
5 | import com.intellij.notification.impl.NotificationFullContent
6 | import com.sourcegraph.Icons
7 | import com.sourcegraph.cody.agent.action.CodyAgentRestartAction
8 | import com.sourcegraph.common.CodyBundle
9 | import com.sourcegraph.common.NotificationGroups
10 |
11 | class CodyConnectionTimeoutExceptionNotification :
12 | Notification(
13 | NotificationGroups.SOURCEGRAPH_ERRORS,
14 | CodyBundle.getString("notifications.cody-connection-timeout.title"),
15 | CodyBundle.getString("notifications.cody-connection-timeout.detail"),
16 | NotificationType.WARNING),
17 | NotificationFullContent {
18 |
19 | init {
20 | icon = Icons.CodyLogoSlash
21 | addAction(CodyAgentRestartAction())
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/Icons.java:
--------------------------------------------------------------------------------
1 | package com.sourcegraph;
2 |
3 | import com.intellij.openapi.util.IconLoader;
4 | import javax.swing.*;
5 |
6 | public interface Icons {
7 | Icon SourcegraphLogo = IconLoader.getIcon("/icons/sourcegraphLogo.svg", Icons.class);
8 | Icon CodyLogo = IconLoader.getIcon("/icons/codyLogo.svg", Icons.class);
9 | Icon CodyLogoSlash = IconLoader.getIcon("/icons/cody-logo-heavy-slash.svg", Icons.class);
10 | Icon GearPlain = IconLoader.getIcon("/icons/gearPlain.svg", Icons.class);
11 | Icon RepoIgnored = IconLoader.getIcon("/icons/repo-ignored.svg", Icons.class);
12 | Icon RepoHostBitbucket = IconLoader.getIcon("/icons/repo-host-bitbucket.svg", Icons.class);
13 | Icon RepoHostGeneric = IconLoader.getIcon("/icons/repo-host-generic.svg", Icons.class);
14 | Icon RepoHostGitHub = IconLoader.getIcon("/icons/repo-host-github.svg", Icons.class);
15 | Icon RepoHostGitlab = IconLoader.getIcon("/icons/repo-host-gitlab.svg", Icons.class);
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/config/ui/lang/LanguageCheckboxColumn.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.config.ui.lang
2 |
3 | import com.intellij.ui.components.JBCheckBox
4 | import com.intellij.util.ui.ColumnInfo
5 | import javax.swing.JTable
6 |
7 | class LanguageCheckboxColumn(private val languageTable: AutocompleteLanguageTable) :
8 | ColumnInfo("") {
9 | override fun isCellEditable(languageEntry: LanguageEntry): Boolean {
10 | return languageTable.isEnabled
11 | }
12 |
13 | override fun getColumnClass(): Class<*> {
14 | return Boolean::class.java
15 | }
16 |
17 | override fun valueOf(languageEntry: LanguageEntry): Boolean {
18 | return !languageEntry.isBlacklisted
19 | }
20 |
21 | override fun setValue(languageEntry: LanguageEntry, value: Boolean) {
22 | languageEntry.isBlacklisted = !value
23 | }
24 |
25 | override fun getWidth(table: JTable): Int {
26 | return JBCheckBox().preferredSize.width
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/ui/web/WebPanelFileType.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.ui.web
2 |
3 | import com.intellij.openapi.fileTypes.FileType
4 | import com.intellij.openapi.util.NlsContexts
5 | import com.intellij.openapi.util.NlsSafe
6 | import javax.swing.Icon
7 |
8 | /// A file type which causes a WebPanelEditor to be created to 'edit' the file and present a Webview
9 | // panel.
10 | class WebPanelFileType : FileType {
11 | companion object {
12 | @JvmStatic val INSTANCE = WebPanelFileType()
13 | }
14 |
15 | override fun getName(): String {
16 | return "SourcegraphWebPanel"
17 | }
18 |
19 | override fun getDescription(): @NlsContexts.Label String {
20 | return "Sourcegraph Cody Web Panel"
21 | }
22 |
23 | override fun getDefaultExtension(): @NlsSafe String {
24 | return ""
25 | }
26 |
27 | override fun getIcon(): Icon? {
28 | return null
29 | }
30 |
31 | override fun isBinary(): Boolean {
32 | return true
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/config/ui/lang/LanguageEntry.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.config.ui.lang
2 |
3 | import com.intellij.lang.Language
4 | import com.sourcegraph.config.ConfigUtil
5 | import java.util.stream.Collectors
6 |
7 | class LanguageEntry(val language: Language, var isBlacklisted: Boolean) {
8 | companion object {
9 | val ANY = LanguageEntry(Language.ANY, false)
10 |
11 | fun getRegisteredLanguageEntries(): List {
12 | val blacklistedLanguageIds: List = ConfigUtil.getBlacklistedAutocompleteLanguageIds()
13 | return Language.getRegisteredLanguages()
14 | .stream()
15 | .filter { l ->
16 | l != Language.ANY
17 | } // skip ANY, since it doesn't correspond to any actual language
18 | .map { l -> LanguageEntry(l!!, blacklistedLanguageIds.contains(l.id)) }
19 | .collect(Collectors.toList())
20 | .sortedBy { le -> le.language.displayName }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/find/HeaderPanel.java:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.find;
2 |
3 | import com.intellij.util.ui.JBEmptyBorder;
4 | import com.intellij.util.ui.components.BorderLayoutPanel;
5 | import com.sourcegraph.Icons;
6 | import com.sourcegraph.config.GoToPluginSettingsButtonFactory;
7 | import java.awt.*;
8 | import javax.swing.*;
9 |
10 | public class HeaderPanel extends BorderLayoutPanel {
11 | public HeaderPanel() {
12 | super();
13 | setBorder(new JBEmptyBorder(5, 5, 2, 5));
14 |
15 | JPanel title = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
16 | title.setBorder(new JBEmptyBorder(2, 0, 0, 0));
17 | title.add(new JLabel("Find with Sourcegraph", Icons.SourcegraphLogo, SwingConstants.LEFT));
18 |
19 | JPanel buttons = new JPanel(new FlowLayout(FlowLayout.RIGHT, 0, 0));
20 | buttons.add(GoToPluginSettingsButtonFactory.createGoToPluginSettingsButton());
21 |
22 | add(title, BorderLayout.WEST);
23 | add(buttons, BorderLayout.EAST);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/InstructionsInputTextArea.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit
2 |
3 | import com.intellij.ui.SimpleTextAttributes
4 | import com.intellij.ui.components.JBTextArea
5 | import com.intellij.ui.components.TextComponentEmptyText
6 | import com.intellij.util.ui.JBUI
7 | import java.util.function.Predicate
8 |
9 | class InstructionsInputTextArea : JBTextArea() {
10 |
11 | init {
12 | lineWrap = true
13 | wrapStyleWord = true
14 | border = JBUI.Borders.empty(JBUI.insets(10, 15))
15 |
16 | emptyText.appendText(GHOST_TEXT, SimpleTextAttributes.GRAY_ATTRIBUTES)
17 | putClientProperty(
18 | TextComponentEmptyText.STATUS_VISIBLE_FUNCTION,
19 | Predicate { c: JBTextArea -> c.text.isEmpty() })
20 | }
21 |
22 | companion object {
23 | // TODO: Put this back when @-includes are in
24 | // const val GHOST_TEXT = "Instructions (@ to include code)"
25 | const val GHOST_TEXT = "Type what changes you want to make to this file..."
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/resources/icons/actions/hide.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/main/resources/icons/chat/chat_command.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/main/resources/icons/actions/hide_dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/autocomplete/action/CodyActionPromoter.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.autocomplete.action
2 |
3 | import com.intellij.openapi.actionSystem.ActionPromoter
4 | import com.intellij.openapi.actionSystem.AnAction
5 | import com.intellij.openapi.actionSystem.DataContext
6 | import com.intellij.openapi.editor.actionSystem.EditorAction
7 |
8 | class CodyActionPromoter : ActionPromoter {
9 | override fun promote(
10 | actions: MutableList,
11 | context: DataContext
12 | ): MutableList? {
13 | return if (actions.stream().noneMatch { action: AnAction? ->
14 | action is CodyAction && action is EditorAction
15 | }) {
16 | null
17 | } else {
18 | val result: ArrayList = ArrayList(actions)
19 | result.sortWith { a: AnAction?, b: AnAction? ->
20 | when {
21 | a is CodyAction -> -1
22 | b is CodyAction -> 1
23 | else -> 0
24 | }
25 | }
26 | result
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/statusbar/CodyDisableAutocompleteAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.statusbar
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent
4 | import com.sourcegraph.cody.auth.CodyAccount
5 | import com.sourcegraph.cody.autocomplete.CodyAutocompleteManager
6 | import com.sourcegraph.cody.config.CodyApplicationSettings
7 | import com.sourcegraph.common.ui.DumbAwareEDTAction
8 | import com.sourcegraph.config.ConfigUtil
9 |
10 | class CodyDisableAutocompleteAction : DumbAwareEDTAction("Disable Cody Autocomplete") {
11 | override fun actionPerformed(e: AnActionEvent) {
12 | CodyApplicationSettings.instance.isCodyAutocompleteEnabled = false
13 | CodyAutocompleteManager.instance.clearAutocompleteSuggestionsForAllProjects()
14 | }
15 |
16 | override fun update(e: AnActionEvent) {
17 | super.update(e)
18 | e.presentation.isEnabledAndVisible =
19 | ConfigUtil.isCodyEnabled() &&
20 | ConfigUtil.isCodyAutocompleteEnabled() &&
21 | CodyAccount.hasActiveAccount()
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/cody/agent/WebviewPostMessageParams.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.agent
2 |
3 | import com.sourcegraph.cody.agent.protocol.WebviewOptions
4 |
5 | data class WebviewRegisterWebviewViewProviderParams(
6 | val viewId: String,
7 | val retainContextWhenHidden: Boolean
8 | )
9 |
10 | data class WebviewPostMessageStringEncodedParams(val id: String, val stringEncodedMessage: String)
11 |
12 | data class WebviewSetHtmlParams(val handle: String, val html: String)
13 |
14 | data class WebviewSetIconPathParams(val handle: String, val iconPathUri: String?)
15 |
16 | data class WebviewSetOptionsParams(val handle: String, val options: WebviewOptions)
17 |
18 | data class WebviewSetTitleParams(val handle: String, val title: String)
19 |
20 | data class WebviewRevealParams(val handle: String, val viewColumn: Int, val preserveFocus: Boolean)
21 |
22 | // When the server initiates dispose, this is sent to the client.
23 | data class WebviewDisposeParams(val handle: String)
24 |
25 | data class ConfigFeatures(val serverSentModels: Boolean)
26 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Test plan
2 |
3 |
24 |
--------------------------------------------------------------------------------
/scripts/next-release.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -eu
3 |
4 | # Check the number of arguments
5 | if [ "$#" -ne 1 ]; then
6 | echo "Usage: $0 [--major | --minor | --patch]"
7 | exit 1
8 | fi
9 |
10 | LAST_MAJOR_MINOR_ZERO_RELEASE=$(git tag -l | grep "v\d*\\.\d*\\.\d*" | uniq | sort -V | tail -1 | sed 's/-nightly//' | sed 's/-experimental//')
11 | MAJOR=$(echo $LAST_MAJOR_MINOR_ZERO_RELEASE | sed 's/v//' | cut -d. -f1)
12 | MINOR=$(echo $LAST_MAJOR_MINOR_ZERO_RELEASE | sed 's/v//' | cut -d. -f2)
13 | PATCH=$(echo $LAST_MAJOR_MINOR_ZERO_RELEASE | sed 's/v//' | cut -d. -f3)
14 |
15 | NEXT_RELEASE_ARG="$1"
16 | # Check the argument and take appropriate action
17 | if [ "$NEXT_RELEASE_ARG" == "--major" ]; then
18 | MAJOR=$(($MAJOR+1))
19 | echo "$MAJOR.0.0"
20 | elif [ "$NEXT_RELEASE_ARG" == "--minor" ]; then
21 | MINOR=$((MINOR+1))
22 | echo "$MAJOR.$MINOR.0"
23 | elif [ "$NEXT_RELEASE_ARG" == "--patch" ]; then
24 | PATCH=$(($PATCH+1))
25 | echo "$MAJOR.$MINOR.$PATCH"
26 | else
27 | echo "Invalid argument. Usage: $0 [--major | --minor | --patch]"
28 | exit 1
29 | fi
30 |
--------------------------------------------------------------------------------
/src/main/resources/icons/edit/document_code.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/agent/protocol/Webview.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.agent.protocol
2 |
3 | data class WebviewCreateWebviewPanelPortMapping(val webviewPort: Int, val extensionHostPort: Int)
4 |
5 | data class WebviewOptions(
6 | val enableScripts: Boolean,
7 | val enableForms: Boolean,
8 | // boolean | readonly string[]
9 | val enableCommandUris: Any,
10 | // Note, we model "missing" here because interpreting the default
11 | // depends on the current workspace root.
12 | val localResourceRoots: List,
13 | val portMapping: List,
14 | val enableFindWidget: Boolean,
15 | val retainContextWhenHidden: Boolean,
16 | )
17 |
18 | data class WebviewCreateWebviewPanelShowOptions(
19 | val preserveFocus: Boolean,
20 | val viewColumn: Int,
21 | )
22 |
23 | data class WebviewCreateWebviewPanelParams(
24 | val handle: String,
25 | val viewType: String,
26 | val title: String,
27 | val showOptions: WebviewCreateWebviewPanelShowOptions,
28 | val options: WebviewOptions
29 | )
30 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/auth/deprecated/DeprecatedCodyPersistentAccounts.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.auth.deprecated
2 |
3 | import com.intellij.openapi.components.PersistentStateComponent
4 | import com.intellij.openapi.components.SettingsCategory
5 | import com.intellij.openapi.components.State
6 | import com.intellij.openapi.components.Storage
7 |
8 | @State(
9 | name = "CodyAccounts",
10 | storages =
11 | [
12 | Storage(value = "cody_accounts.xml"),
13 | ],
14 | reportStatistic = false,
15 | category = SettingsCategory.TOOLS)
16 | class DeprecatedCodyPersistentAccounts : PersistentStateComponent> {
17 |
18 | private var state = emptyArray()
19 |
20 | var accounts: Set
21 | get() = state.toSet()
22 | set(value) {
23 | state = value.toTypedArray()
24 | }
25 |
26 | override fun getState(): Array = state
27 |
28 | override fun loadState(state: Array) {
29 | this.state = state
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/autocomplete/render/CodyAutocompleteSingleLineRenderer.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.autocomplete.render
2 |
3 | import com.intellij.openapi.editor.Editor
4 | import com.intellij.openapi.editor.Inlay
5 | import com.intellij.openapi.editor.markup.TextAttributes
6 | import com.sourcegraph.cody.agent.protocol_generated.AutocompleteItem
7 | import java.awt.Graphics
8 | import java.awt.Rectangle
9 |
10 | class CodyAutocompleteSingleLineRenderer(
11 | text: String,
12 | items: List,
13 | editor: Editor,
14 | type: AutocompleteRendererType
15 | ) : CodyAutocompleteElementRenderer(text, items, editor, type) {
16 | override fun paint(
17 | inlay: Inlay<*>,
18 | g: Graphics,
19 | targetRegion: Rectangle,
20 | textAttributes: TextAttributes
21 | ) {
22 | val fontInfo = fontInfoForText(text)
23 | g.font = fontInfo.font
24 | g.color = themeAttributes.foregroundColor
25 | val x = targetRegion.x
26 | val y = targetRegion.y + fontYOffset(fontInfo).toInt()
27 | g.drawString(text, x, y)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
2 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
3 |
4 | *.jar
5 | !gradle-wrapper.jar
6 |
7 | # User local IDEA configuration files
8 | .idea/
9 | .run/
10 |
11 | # IntelliJ project
12 | *.iml
13 |
14 | # User local IDEA run configurations
15 | .run/
16 |
17 | # Build output & caches for IntelliJ plugin development
18 | build/
19 | idea-sandbox/
20 | .gradle/
21 |
22 | ## File-based project format:
23 | *.iws
24 |
25 | # IntelliJ
26 | /out/
27 | .intellijPlatform
28 |
29 | # mpeltonen/sbt-idea plugin
30 | .idea_modules/
31 |
32 | # JIRA plugin
33 | atlassian-ide-plugin.xml
34 |
35 | # Crashlytics plugin (for Android Studio and IntelliJ)
36 | com_crashlytics_export_strings.xml
37 | crashlytics.properties
38 | crashlytics-build.properties
39 | fabric.properties
40 |
41 | # JavaScript resources
42 | src/main/resources/dist/*
43 |
44 | # VSCode langserver artifacts
45 | /bin/
46 | .DS_Store
47 | /src/main/kotlin/com/sourcegraph/cody/agent/protocol_generated/*
48 |
--------------------------------------------------------------------------------
/.github/workflows/stable-release.yml:
--------------------------------------------------------------------------------
1 | name: Stable Release
2 | on:
3 | workflow_dispatch
4 | jobs:
5 | publish:
6 | runs-on: ubuntu-latest
7 | steps:
8 | - uses: actions/checkout@v4
9 | - uses: actions/setup-node@v4
10 | with:
11 | node-version: 20
12 | - uses: actions/setup-java@v4
13 | with:
14 | distribution: temurin
15 | java-version: 17
16 | cache: gradle
17 | # See note about QEMU and binfmt requirement here https://github.com/vercel/pkg#targets
18 | - name: Set up QEMU
19 | id: qemu
20 | uses: docker/setup-qemu-action@v3
21 | with:
22 | image: tonistiigi/binfmt:latest
23 | platforms: all
24 | - name: Gradle Wrapper Validation
25 | uses: gradle/wrapper-validation-action@v3
26 | - run: yarn global add pnpm@8.6.7
27 | - run: |
28 | echo "RELEASE_VERSION=$(./scripts/version-from-git-tag.sh)" >> $GITHUB_ENV
29 | - run: ./gradlew "-PpluginVersion=$RELEASE_VERSION" publishPlugin
30 | env:
31 | PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
32 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/find/SourcegraphVirtualFile.java:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.find;
2 |
3 | import com.intellij.testFramework.LightVirtualFile;
4 | import com.intellij.util.LocalTimeCounter;
5 | import org.jetbrains.annotations.NotNull;
6 |
7 | public class SourcegraphVirtualFile extends LightVirtualFile {
8 | private final String repoUrl;
9 | private final String commit;
10 | private final String path;
11 |
12 | public SourcegraphVirtualFile(
13 | @NotNull String name,
14 | @NotNull CharSequence content,
15 | String repoUrl,
16 | String commit,
17 | String path) {
18 | super(name, null, content, LocalTimeCounter.currentTime());
19 | this.repoUrl = repoUrl;
20 | this.commit = commit;
21 | this.path = path;
22 | }
23 |
24 | public String getRepoUrl() {
25 | return repoUrl;
26 | }
27 |
28 | public String getCommit() {
29 | return commit;
30 | }
31 |
32 | @NotNull
33 | public String getRelativePath() {
34 | return path;
35 | }
36 |
37 | @NotNull
38 | @Override
39 | public String getPath() {
40 | return repoUrl + " > " + path;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/pluginIcon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
28 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/internals/InternalsStatusBarWidgetFactory.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.internals
2 |
3 | import com.intellij.openapi.project.Project
4 | import com.intellij.openapi.util.Disposer
5 | import com.intellij.openapi.wm.StatusBar
6 | import com.intellij.openapi.wm.StatusBarWidget
7 | import com.intellij.openapi.wm.StatusBarWidgetFactory
8 | import com.sourcegraph.config.ConfigUtil
9 |
10 | class InternalsStatusBarWidgetFactory : StatusBarWidgetFactory {
11 | override fun getId(): String = ID
12 |
13 | override fun getDisplayName(): String = "⚠\uFE0F Cody Internals"
14 |
15 | override fun isAvailable(project: Project): Boolean {
16 | return ConfigUtil.isFeatureFlagEnabled("cody.feature.internals-menu")
17 | }
18 |
19 | override fun canBeEnabledOn(statusBar: StatusBar): Boolean = true
20 |
21 | override fun createWidget(project: Project): StatusBarWidget = InternalsStatusBarWidget(project)
22 |
23 | override fun disposeWidget(widget: StatusBarWidget) {
24 | Disposer.dispose(widget)
25 | }
26 |
27 | companion object {
28 | const val ID = "cody.internalsStatusBarWidget"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/resources/icons/sourcegraphLogo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
28 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/common/ui/DumbAwareEDTAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.common.ui
2 |
3 | import com.intellij.openapi.actionSystem.ActionUpdateThread
4 | import com.intellij.openapi.actionSystem.AnActionEvent
5 | import com.intellij.openapi.project.DumbAwareAction
6 | import com.intellij.openapi.util.NlsActions
7 | import javax.swing.Icon
8 |
9 | abstract class DumbAwareEDTAction : DumbAwareAction {
10 |
11 | constructor() : super()
12 |
13 | constructor(icon: Icon?) : super(icon)
14 |
15 | constructor(text: @NlsActions.ActionText String?) : super(text)
16 |
17 | constructor(
18 | text: @NlsActions.ActionText String?,
19 | description: @NlsActions.ActionDescription String?,
20 | icon: Icon?
21 | ) : super(text, description, icon)
22 |
23 | override fun getActionUpdateThread(): ActionUpdateThread {
24 | return ActionUpdateThread.EDT
25 | }
26 | }
27 |
28 | class SimpleDumbAwareEDTAction(
29 | text: @NlsActions.ActionText String? = null,
30 | private val action: (AnActionEvent) -> Unit
31 | ) : DumbAwareEDTAction(text) {
32 | override fun actionPerformed(e: AnActionEvent) {
33 | action(e)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/utils/CodyProjectUtil.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.utils
2 |
3 | import com.intellij.ide.lightEdit.LightEdit
4 | import com.intellij.openapi.project.Project
5 |
6 | object CodyProjectUtil {
7 | @JvmStatic
8 | fun isProjectAvailable(project: Project?): Boolean {
9 | return project != null && !project.isDisposed
10 | }
11 |
12 | fun isProjectSupported(project: Project?): Boolean {
13 | return if (isProjectorEnabled()) {
14 | true
15 | } else {
16 | // Light edit is a mode when users can edit a single file with IntelliJ without loading an
17 | // entire project. We lean on the conservative side for now and don't support Cody for
18 | // LightEdit projects.
19 | !LightEdit.owns(project)
20 | }
21 | }
22 |
23 | /**
24 | * Projector is a JetBrains project that runs IntelliJ on a server as a remote IDE. Users
25 | * interface with IntelliJ through a JavaScript client, either in the browser or an Electron.js
26 | * client.
27 | */
28 | private fun isProjectorEnabled(): Boolean {
29 | return "true" == System.getProperty("org.jetbrains.projector.server.enable")
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/resources/icons/codyLogo.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/initialization/PrettyTimer.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.initialization
2 |
3 | import java.time.Duration
4 | import java.time.Instant
5 |
6 | class PrettyTimer {
7 | val start = Instant.now()
8 |
9 | fun elapsed(): Duration {
10 | return Duration.between(start, Instant.now())
11 | }
12 |
13 | companion object {
14 | @JvmStatic
15 | fun debugTask(name: String, fn: () -> T): T {
16 | val timer = PrettyTimer()
17 | val result = fn()
18 | println("Task '$name' - $timer")
19 | return result
20 | }
21 | }
22 |
23 | override fun toString(): String {
24 | val duration = elapsed()
25 | val hours = duration.toHours()
26 | val minutes = duration.toMinutes() % 60
27 | val seconds = duration.seconds % 60
28 | val millis = duration.toMillis() % 1000
29 |
30 | return when {
31 | hours > 0 -> String.format("%dhr%02dmin%02ds", hours, minutes, seconds)
32 | minutes > 0 -> String.format("%dmin%02ds", minutes, seconds)
33 | seconds > 0 -> String.format("%ds%03dms", seconds, millis)
34 | else -> String.format("%dms", millis)
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/common/ErrorNotification.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.common
2 |
3 | import com.intellij.notification.Notification
4 | import com.intellij.notification.NotificationType
5 | import com.intellij.notification.Notifications
6 | import com.intellij.openapi.actionSystem.AnAction
7 | import com.intellij.openapi.project.Project
8 | import com.sourcegraph.Icons
9 | import com.sourcegraph.common.ui.SimpleDumbAwareEDTAction
10 |
11 | object ErrorNotification {
12 | fun show(project: Project?, errorMessage: String) {
13 | val notification = create(errorMessage)
14 | val dismissAction: AnAction = SimpleDumbAwareEDTAction("Dismiss") { notification.expire() }
15 | notification.addAction(dismissAction)
16 | Notifications.Bus.notify(notification)
17 | notification.notify(project)
18 | }
19 |
20 | fun create(errorMessage: String): Notification {
21 | val notification =
22 | Notification(
23 | NotificationGroups.SOURCEGRAPH_ERRORS,
24 | "Sourcegraph",
25 | errorMessage,
26 | NotificationType.WARNING)
27 | notification.setIcon(Icons.CodyLogo)
28 | return notification
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/api/SourcegraphApiRequests.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.api
2 |
3 | import com.intellij.openapi.progress.ProgressIndicator
4 |
5 | object SourcegraphApiRequests {
6 | class CurrentUser(
7 | private val executor: SourcegraphApiRequestExecutor,
8 | private val progressIndicator: ProgressIndicator
9 | ) {
10 | fun getDetails(): CodyAccountDetails =
11 | getCurrentUser(SourcegraphGQLQueries.getUserDetails, CurrentUserDetailsWrapper::class.java)
12 | .currentUser
13 |
14 | private fun getCurrentUser(queryName: String, clazz: Class): T =
15 | executor.execute(
16 | progressIndicator,
17 | SourcegraphApiRequest.Post.GQLQuery(
18 | executor.server.toGraphQLUrl(), queryName, null, clazz))
19 |
20 | data class CurrentUserDetailsWrapper(val currentUser: CodyAccountDetails)
21 |
22 | class CodyAccountDetails(
23 | val id: String,
24 | val username: String,
25 | val displayName: String?,
26 | val avatarURL: String?
27 | ) {
28 | val name: String
29 | get() = displayName ?: username
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/history/HistoryService.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.history
2 |
3 | import com.intellij.openapi.components.Service
4 | import com.intellij.openapi.components.SimplePersistentStateComponent
5 | import com.intellij.openapi.components.State
6 | import com.intellij.openapi.components.Storage
7 | import com.intellij.openapi.components.service
8 | import com.intellij.openapi.project.Project
9 | import com.sourcegraph.cody.history.state.AccountData
10 | import com.sourcegraph.cody.history.state.ChatState
11 | import com.sourcegraph.cody.history.state.HistoryState
12 |
13 | @State(name = "ChatHistory", storages = [Storage("cody_history.xml")])
14 | @Service(Service.Level.PROJECT)
15 | class HistoryService : SimplePersistentStateComponent(HistoryState()) {
16 |
17 | @Synchronized
18 | fun getChatHistoryFor(accountId: String): List? = findEntry(accountId)?.chats
19 |
20 | private fun findEntry(accountId: String): AccountData? =
21 | state.accountData.find { it.accountId == accountId }
22 |
23 | companion object {
24 | @JvmStatic fun getInstance(project: Project): HistoryService = project.service()
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/autocomplete/action/TriggerAutocompleteActionHandler.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.autocomplete.action
2 |
3 | import com.intellij.openapi.actionSystem.DataContext
4 | import com.intellij.openapi.diagnostic.Logger
5 | import com.intellij.openapi.editor.Caret
6 | import com.intellij.openapi.editor.Editor
7 | import com.intellij.openapi.editor.actionSystem.EditorActionHandler
8 | import com.sourcegraph.cody.autocomplete.CodyAutocompleteManager
9 | import com.sourcegraph.cody.vscode.InlineCompletionTriggerKind
10 | import com.sourcegraph.utils.CodyEditorUtil
11 |
12 | class TriggerAutocompleteActionHandler : EditorActionHandler() {
13 | val logger = Logger.getInstance(TriggerAutocompleteActionHandler::class.java)
14 |
15 | override fun isEnabledForCaret(editor: Editor, caret: Caret, dataContext: DataContext): Boolean =
16 | CodyEditorUtil.isEditorInstanceSupported(editor)
17 |
18 | override fun doExecute(editor: Editor, caret: Caret?, dataContext: DataContext) {
19 | val offset = caret?.offset ?: editor.caretModel.currentCaret.offset
20 | CodyAutocompleteManager.instance.triggerAutocomplete(
21 | editor, offset, InlineCompletionTriggerKind.INVOKE)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/listeners/CodyFocusChangeListener.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.listeners
2 |
3 | import com.intellij.openapi.editor.Editor
4 | import com.intellij.openapi.editor.ex.FocusChangeListener
5 | import com.intellij.openapi.project.Project
6 | import com.sourcegraph.cody.agent.CodyAgent
7 | import com.sourcegraph.cody.agent.CodyAgentService
8 | import com.sourcegraph.cody.agent.protocol_extensions.ProtocolTextDocumentExt
9 | import com.sourcegraph.cody.agent.protocol_generated.TextDocument_DidFocusParams
10 | import com.sourcegraph.cody.ignore.IgnoreOracle
11 |
12 | class CodyFocusChangeListener(val project: Project) : FocusChangeListener {
13 |
14 | override fun focusGained(editor: Editor) {
15 | if (editor.project != project) {
16 | return
17 | }
18 |
19 | ProtocolTextDocumentExt.fromEditor(editor)?.let { textDocument ->
20 | EditorChangesBus.documentChanged(project, textDocument)
21 | CodyAgentService.withAgent(project) { agent: CodyAgent ->
22 | agent.server.textDocument_didFocus(TextDocument_DidFocusParams(textDocument.uri))
23 | }
24 | IgnoreOracle.getInstance(project).focusedFileDidChange(textDocument.uri)
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/actions/EditCodeAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit.actions
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent
4 | import com.intellij.openapi.diagnostic.Logger
5 | import com.sourcegraph.cody.agent.protocol_generated.EditTask
6 | import com.sourcegraph.cody.edit.EditCommandPrompt
7 | import java.util.concurrent.ConcurrentHashMap
8 |
9 | class EditCodeAction :
10 | BaseEditCodeAction({ editor ->
11 | val project = editor.project
12 | if (project != null) {
13 | EditCommandPrompt(project, editor, "Edit Code with Cody")
14 | } else {
15 | logger.warn("EditCodeAction invoked with null project")
16 | }
17 | }) {
18 |
19 | override fun update(event: AnActionEvent) {
20 | super.update(event)
21 | event.presentation.isEnabledAndVisible =
22 | event.presentation.isEnabledAndVisible &&
23 | (event.project?.let { !EditCommandPrompt.isVisible(it) } ?: true)
24 | }
25 |
26 | companion object {
27 | val logger = Logger.getInstance(EditCodeAction::class.java)
28 | val completedEditTasks = ConcurrentHashMap()
29 |
30 | const val ID: String = "cody.editCodeAction"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/history/state/ChatState.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.history.state
2 |
3 | import com.intellij.openapi.components.BaseState
4 | import com.intellij.util.xmlb.annotations.OptionTag
5 | import com.intellij.util.xmlb.annotations.Tag
6 |
7 | @Tag("chat")
8 | class ChatState() : BaseState() {
9 | constructor(internalId: String) : this() {
10 | this.internalId = internalId
11 | }
12 |
13 | @get:OptionTag(tag = "internalId", nameAttribute = "") var internalId: String? by string()
14 |
15 | @get:OptionTag(tag = "messages", nameAttribute = "")
16 | var messages: MutableList by list()
17 |
18 | @get:OptionTag(tag = "updatedAt", nameAttribute = "") var updatedAt: String? by string()
19 |
20 | @Deprecated("Use `llm` instead.")
21 | @get:OptionTag(tag = "model", nameAttribute = "")
22 | var model: String? by string()
23 |
24 | @get:OptionTag(tag = "llm", nameAttribute = "") var llm: LLMState? by property()
25 |
26 | @Deprecated("")
27 | @get:OptionTag(tag = "accountId", nameAttribute = "")
28 | var accountId: String? by string()
29 |
30 | @get:OptionTag(tag = "enhancedContext", nameAttribute = "")
31 | var enhancedContext: EnhancedContextState? by property()
32 | }
33 |
--------------------------------------------------------------------------------
/src/integrationTest/kotlin/com/sourcegraph/cody/util/RepeatableSuite.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.util
2 |
3 | import org.junit.runners.Suite
4 | import org.junit.runners.model.InitializationError
5 | import org.junit.runners.model.RunnerBuilder
6 |
7 | class RepeatableSuite(klass: Class<*>, builder: RunnerBuilder?) :
8 | Suite(builder, klass, getAnnotatedClasses(klass)) {
9 |
10 | init {
11 | if (repeatTimes < 1)
12 | throw IllegalStateException("Invalid value for repeatTimes (${repeatTimes} < 1)")
13 | }
14 |
15 | companion object {
16 |
17 | private val repeatTimes: Int = System.getProperty("repeatTests")?.toIntOrNull() ?: 1
18 |
19 | @Throws(InitializationError::class)
20 | fun getAnnotatedClasses(klass: Class<*>): Array> {
21 | val annotation = klass.getAnnotation(SuiteClasses::class.java)
22 | if (annotation == null) {
23 | throw InitializationError(
24 | String.format("class '%s' must have a SuiteClasses annotation", klass.name))
25 | } else {
26 | return annotation.value
27 | .map { it.java }
28 | .map { l -> List(repeatTimes) { l } }
29 | .flatten()
30 | .toTypedArray()
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/config/GoToPluginSettingsButtonFactory.java:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.config;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.Presentation;
5 | import com.intellij.openapi.actionSystem.impl.ActionButton;
6 | import com.intellij.util.IconUtil;
7 | import com.intellij.util.ui.JBDimension;
8 | import com.intellij.util.ui.JBUI;
9 | import com.sourcegraph.Icons;
10 | import com.sourcegraph.cody.config.actions.OpenCodySettingsEditorAction;
11 | import javax.swing.*;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | public class GoToPluginSettingsButtonFactory {
15 |
16 | @NotNull
17 | public static ActionButton createGoToPluginSettingsButton() {
18 | JBDimension actionButtonSize = JBUI.size(22, 22);
19 |
20 | AnAction action = new OpenCodySettingsEditorAction();
21 | Presentation presentation = new Presentation("Open Plugin Settings");
22 |
23 | ActionButton button =
24 | new ActionButton(
25 | action, presentation, "Find with Sourcegraph popup header", actionButtonSize);
26 |
27 | Icon scaledIcon = IconUtil.scale(Icons.GearPlain, button, 13f / 12f);
28 | presentation.setIcon(scaledIcon);
29 |
30 | return button;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/history/state/LLMState.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.history.state
2 |
3 | import com.intellij.openapi.components.BaseState
4 | import com.intellij.util.xmlb.annotations.OptionTag
5 | import com.intellij.util.xmlb.annotations.Tag
6 | import com.sourcegraph.cody.agent.protocol_generated.Model
7 |
8 | @Tag("llm")
9 | class LLMState : BaseState() {
10 | @get:OptionTag(tag = "model", nameAttribute = "") var model: String? by string()
11 |
12 | @get:OptionTag(tag = "title", nameAttribute = "") var title: String? by string()
13 |
14 | @get:OptionTag(tag = "provider", nameAttribute = "") var provider: String? by string()
15 |
16 | @get:OptionTag(tag = "tags", nameAttribute = "") var tags: MutableList by list()
17 |
18 | @get:OptionTag(tag = "usage", nameAttribute = "") var usage: MutableList by list()
19 |
20 | companion object {
21 | fun fromChatModel(chatModel: Model): LLMState {
22 | return LLMState().also {
23 | it.model = chatModel.id
24 | it.title = chatModel.title
25 | it.provider = chatModel.provider
26 | it.tags = chatModel.tags?.toMutableList() ?: mutableListOf()
27 | it.usage = chatModel.usage.toMutableList()
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/website/CopyAction.java:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.website;
2 |
3 | import com.intellij.notification.Notification;
4 | import com.intellij.notification.NotificationType;
5 | import com.intellij.notification.Notifications;
6 | import com.intellij.openapi.ide.CopyPasteManager;
7 | import com.intellij.openapi.project.Project;
8 | import com.sourcegraph.common.NotificationGroups;
9 | import java.awt.datatransfer.StringSelection;
10 | import org.jetbrains.annotations.NotNull;
11 |
12 | public class CopyAction extends FileActionBase {
13 | @Override
14 | protected void handleFileUri(@NotNull Project project, @NotNull String uri) {
15 | // Remove utm tags for sharing
16 | String urlWithoutUtm = uri.replaceAll("(&utm_product_name=)(.*)", "");
17 |
18 | // Copy file uri to clipboard
19 | CopyPasteManager.getInstance().setContents(new StringSelection(urlWithoutUtm));
20 |
21 | // Display notification
22 | Notification notification =
23 | new Notification(
24 | NotificationGroups.SOURCEGRAPH_URL_SHARING,
25 | "Sourcegraph",
26 | "File URL copied to clipboard: " + urlWithoutUtm,
27 | NotificationType.INFORMATION);
28 | Notifications.Bus.notify(notification);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/.github/workflows/nightly-release.yml:
--------------------------------------------------------------------------------
1 | name: Nightly Release
2 | on:
3 | push:
4 | tags: [ "*-nightly" ]
5 | jobs:
6 | publish:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v4
10 | - uses: actions/setup-node@v4
11 | with:
12 | node-version: 20
13 | - uses: actions/setup-java@v4
14 | with:
15 | distribution: temurin
16 | java-version: 17
17 | cache: gradle
18 | # See note about QEMU and binfmt requirement here https://github.com/vercel/pkg#targets
19 | - name: Set up QEMU
20 | id: qemu
21 | uses: docker/setup-qemu-action@v3
22 | with:
23 | image: tonistiigi/binfmt:latest
24 | platforms: all
25 | - name: Gradle Wrapper Validation
26 | uses: gradle/wrapper-validation-action@v3
27 | - run: yarn global add pnpm@8.6.7
28 | - run: |
29 | echo "RELEASE_VERSION=$(./scripts/version-from-git-tag.sh)-nightly" >> $GITHUB_ENV
30 | - name: Publish nightly version
31 | run: |
32 | echo "Publishing nightly version ${RELEASE_VERSION}"
33 | ./gradlew "-PpluginVersion=${RELEASE_VERSION}" publishPlugin
34 | env:
35 | PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
36 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/sourcegraph/cody/config/SourcegraphServerPathTest.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.config
2 |
3 | import com.sourcegraph.cody.auth.SourcegraphServerPath
4 | import com.sourcegraph.config.ConfigUtil
5 | import junit.framework.TestCase
6 |
7 | class SourcegraphServerPathTest : TestCase() {
8 |
9 | fun `test path for dotcom`() {
10 | val path = SourcegraphServerPath.from(ConfigUtil.DOTCOM_URL, "")
11 | assertEquals("https://sourcegraph.com/", path.url)
12 | }
13 |
14 | fun `test path with extra slash postfix`() {
15 | val path = SourcegraphServerPath.from("https://sourcegraph.com", "")
16 | assertEquals("https://sourcegraph.com/", path.url)
17 | }
18 |
19 | fun `test path with https prefix`() {
20 | val path = SourcegraphServerPath.from("sourcegraph.com", "")
21 | assertEquals("https://sourcegraph.com/", path.url)
22 | }
23 |
24 | fun `test path with port`() {
25 | val path = SourcegraphServerPath.from("sourcegraph.com:80", "")
26 | assertEquals("https://sourcegraph.com:80/", path.url)
27 | }
28 |
29 | fun `test path with additional path segments`() {
30 | val path = SourcegraphServerPath.from("sourcegraph.com:80/some/path", "")
31 | assertEquals("https://sourcegraph.com:80/some/path/", path.url)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/flake.nix:
--------------------------------------------------------------------------------
1 | {
2 | description = "The Sourcegraph Jetbrains Client developer environment Nix Flake";
3 |
4 | inputs = {
5 | nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
6 | flake-utils.url = "github:numtide/flake-utils";
7 | };
8 |
9 | outputs = { self, nixpkgs, flake-utils }: flake-utils.lib.eachDefaultSystem (system:
10 | let
11 | pkgs = nixpkgs.legacyPackages.${system};
12 | libraries = pkgs.lib.makeLibraryPath (with pkgs; with xorg; [
13 | libXtst
14 | libXext
15 | libX11
16 | libXrender
17 | libXi
18 | freetype
19 | fontconfig.lib
20 | zlib
21 | libsecret
22 | ]);
23 | gradle-wrapped = pkgs.writeShellScriptBin "gradle" ''
24 | export LD_LIBRARY_PATH=${libraries}
25 | exec ${pkgs.gradle.override {
26 | javaToolchains = [ "${pkgs.jdk8}/lib/openjdk" "${pkgs.jdk11}/lib/openjdk" "${pkgs.jdk17}/lib/openjdk" ];
27 | }}/bin/gradle "$@"
28 | '';
29 | in
30 | {
31 | devShells.default = pkgs.mkShell {
32 | nativeBuildInputs = with pkgs; [
33 | gradle-wrapped
34 | nodejs_20
35 | nodejs_20.pkgs.pnpm
36 | nodejs_20.pkgs.typescript
37 | ];
38 | };
39 | });
40 | }
41 |
--------------------------------------------------------------------------------
/.github/workflows/experimental-release.yml:
--------------------------------------------------------------------------------
1 | name: Experimental Release
2 | on:
3 | push:
4 | tags: [ "*-experimental" ]
5 | jobs:
6 | publish:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v4
10 | - uses: actions/setup-node@v4
11 | with:
12 | node-version: 20
13 | - uses: actions/setup-java@v4
14 | with:
15 | distribution: temurin
16 | java-version: 17
17 | cache: gradle
18 | # See note about QEMU and binfmt requirement here https://github.com/vercel/pkg#targets
19 | - name: Set up QEMU
20 | id: qemu
21 | uses: docker/setup-qemu-action@v3
22 | with:
23 | image: tonistiigi/binfmt:latest
24 | platforms: all
25 | - name: Gradle Wrapper Validation
26 | uses: gradle/wrapper-validation-action@v3
27 | - run: yarn global add pnpm@8.6.7
28 | - run: |
29 | echo "RELEASE_VERSION=$(./scripts/version-from-git-tag.sh)-experimental" >> $GITHUB_ENV
30 | - name: Publish experimental version
31 | run: |
32 | echo "Publishing experimental version ${RELEASE_VERSION}"
33 | ./gradlew "-PpluginVersion=${RELEASE_VERSION}" publishPlugin
34 | env:
35 | PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
36 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/statusbar/OpenLogAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.statusbar
2 |
3 | import com.intellij.idea.LoggerFactory
4 | import com.intellij.notification.Notification
5 | import com.intellij.notification.NotificationType
6 | import com.intellij.notification.Notifications.Bus
7 | import com.intellij.openapi.actionSystem.AnActionEvent
8 | import com.intellij.openapi.fileEditor.FileEditorManager
9 | import com.intellij.openapi.vfs.LocalFileSystem
10 | import com.intellij.openapi.vfs.VfsUtil
11 | import com.sourcegraph.common.ui.DumbAwareEDTAction
12 |
13 | class OpenLogAction : DumbAwareEDTAction("Open Log To Troubleshoot Issue") {
14 |
15 | override fun actionPerformed(e: AnActionEvent) {
16 | val project = e.project
17 | if (project != null) {
18 | val file =
19 | LocalFileSystem.getInstance().refreshAndFindFileByNioFile(LoggerFactory.getLogFilePath())
20 | if (file != null) {
21 | VfsUtil.markDirtyAndRefresh(true, false, false, *arrayOf(file))
22 | FileEditorManager.getInstance(project).openFile(file, true)
23 | } else {
24 | val title = "Cannot find '" + LoggerFactory.getLogFilePath() + "'"
25 | Bus.notify(Notification("System Messages", title, "", NotificationType.INFORMATION))
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/intellij2023/kotlin/com/intellij/codeInsight/inline/completion/suggestion/InlineCompletionSuggestion.kt:
--------------------------------------------------------------------------------
1 | package com.intellij.codeInsight.inline.completion.suggestion
2 |
3 | import com.intellij.codeInsight.inline.completion.elements.InlineCompletionElement
4 | import com.intellij.openapi.util.UserDataHolderBase
5 | import kotlinx.coroutines.flow.Flow
6 | import kotlinx.coroutines.flow.FlowCollector
7 |
8 | interface InlineCompletionSuggestion {
9 |
10 | object Empty : InlineCompletionSuggestion {}
11 | }
12 |
13 | interface InlineCompletionSingleSuggestion : InlineCompletionSuggestion {
14 |
15 | companion object {
16 |
17 | /** @see [InlineCompletionVariant.build] */
18 | fun build(
19 | data: UserDataHolderBase = UserDataHolderBase(),
20 | buildElements:
21 | suspend FlowCollector.(data: UserDataHolderBase) -> Unit
22 | ): InlineCompletionSingleSuggestion {
23 | return object : InlineCompletionSingleSuggestion {}
24 | }
25 |
26 | /** @see InlineCompletionVariant.build */
27 | fun build(
28 | data: UserDataHolderBase = UserDataHolderBase(),
29 | elements: Flow
30 | ): InlineCompletionSingleSuggestion {
31 | return object : InlineCompletionSingleSuggestion {}
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/config/ui/lang/AutocompleteLanguageTableWrapper.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.config.ui.lang
2 |
3 | import java.awt.BorderLayout
4 | import java.awt.Dimension
5 | import javax.swing.JPanel
6 |
7 | /** Wrapper to be used with JetBrains Kotlin UI DSL */
8 | class AutocompleteLanguageTableWrapper(private val languageTable: AutocompleteLanguageTable) :
9 | JPanel(BorderLayout()) {
10 | private val tableComponent = languageTable.component
11 |
12 | init {
13 | val customHeightDiff = 120
14 | val customPreferredSize =
15 | Dimension(
16 | tableComponent.preferredSize.width,
17 | tableComponent.preferredSize.height + customHeightDiff)
18 | tableComponent.preferredSize = customPreferredSize
19 | add(tableComponent)
20 | }
21 |
22 | fun getBlacklistedLanguageIds(): List {
23 | return languageTable.getBlacklistedLanguageIds()
24 | }
25 |
26 | fun setBlacklistedLanguageIds(blacklistedIds: List) {
27 | languageTable.setBlacklistedLanguageIds(blacklistedIds)
28 | }
29 |
30 | override fun setEnabled(enabled: Boolean) {
31 | super.setEnabled(enabled)
32 | tableComponent.isEnabled = enabled
33 | tableComponent.components.forEach { it.isEnabled = enabled }
34 | languageTable.isEnabled = enabled
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/resources/icons/gearPlain.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/main/resources/icons/gearPlain_dark.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/agent/protocol/RateLimitError.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.agent.protocol
2 |
3 | import com.google.gson.*
4 | import java.lang.reflect.Type
5 | import org.eclipse.lsp4j.jsonrpc.ResponseErrorException
6 |
7 | data class RateLimitError(val upgradeIsAvailable: Boolean, val limit: Int?) {
8 |
9 | companion object {
10 | fun ResponseErrorException.toRateLimitError(): RateLimitError {
11 | val data = responseError.data as JsonPrimitive
12 | val gsonBuilder = GsonBuilder()
13 | gsonBuilder.registerTypeAdapter(RateLimitError::class.java, RateLimitErrorDeserializer())
14 | val gson = gsonBuilder.create()
15 | return gson.fromJson(data.asString, RateLimitError::class.java)
16 | }
17 |
18 | class RateLimitErrorDeserializer : JsonDeserializer {
19 | override fun deserialize(
20 | json: JsonElement,
21 | typeOfT: Type?,
22 | context: JsonDeserializationContext?
23 | ): RateLimitError {
24 | val jsonObject = json.asJsonObject
25 | val errorObject = jsonObject["error"].asJsonObject
26 | val limit = errorObject["limit"]?.asInt
27 | val upgradeIsAvailable = errorObject["upgradeIsAvailable"]?.asBoolean
28 |
29 | return RateLimitError(upgradeIsAvailable ?: false, limit)
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/config/CodySettingsFileChangeListener.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.config
2 |
3 | import com.intellij.openapi.editor.Document
4 | import com.intellij.openapi.fileEditor.FileDocumentManagerListener
5 | import com.intellij.openapi.project.Project
6 | import com.intellij.openapi.vfs.LocalFileSystem
7 | import com.sourcegraph.cody.agent.CodyAgentService
8 | import com.sourcegraph.config.ConfigUtil
9 | import com.sourcegraph.utils.CodyEditorUtil
10 |
11 | class CodySettingsFileChangeListener(private val project: Project) : FileDocumentManagerListener {
12 | override fun beforeDocumentSaving(document: Document) {
13 | val editor = CodyEditorUtil.getEditorForDocument(document) ?: return
14 | if (editor.project != project) {
15 | return
16 | }
17 |
18 | val currentFile = editor.virtualFile
19 | val configFile =
20 | LocalFileSystem.getInstance()
21 | .refreshAndFindFileByNioFile(ConfigUtil.getSettingsFile(project))
22 | if (currentFile == configFile) {
23 | // TODO: it seams that some of the settings changes (like enabling/disabling autocomplete)
24 | // requires agent restart to take effect.
25 | CodyAgentService.withAgentRestartIfNeeded(project) {
26 | it.server.extensionConfiguration_change(
27 | ConfigUtil.getAgentConfiguration(project, document.text))
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/common/BrowserOpener.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.common
2 |
3 | import com.intellij.ide.BrowserUtil
4 | import com.intellij.openapi.diagnostic.Logger
5 | import com.intellij.openapi.project.Project
6 | import com.sourcegraph.common.BrowserErrorNotification.show
7 | import com.sourcegraph.config.ConfigUtil.getServerPath
8 | import java.awt.Desktop
9 | import java.io.IOException
10 | import java.net.URI
11 | import java.net.URISyntaxException
12 |
13 | object BrowserOpener {
14 | fun openRelativeUrlInBrowser(project: Project, relativeUrl: String) {
15 | openInBrowser(project, getServerPath().url + "/" + relativeUrl)
16 | }
17 |
18 | fun openInBrowser(project: Project?, absoluteUrl: String) {
19 | try {
20 | openInBrowser(project, URI(absoluteUrl))
21 | } catch (e: URISyntaxException) {
22 | val logger = Logger.getInstance(BrowserOpener::class.java)
23 | logger.warn("Error while creating URL from \"" + absoluteUrl + "\": " + e.message)
24 | }
25 | }
26 |
27 | fun openInBrowser(project: Project?, uri: URI) {
28 | try {
29 | BrowserUtil.browse(uri)
30 | } catch (e: Exception) {
31 | try {
32 | Desktop.getDesktop().browse(uri)
33 | } catch (e2: IOException) {
34 | show(project, uri)
35 | } catch (e2: UnsupportedOperationException) {
36 | show(project, uri)
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/chat/ui/ErrorPanel.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.chat.ui
2 |
3 | import com.intellij.ui.SimpleTextAttributes
4 | import com.intellij.util.ui.JBUI
5 | import com.sourcegraph.Icons
6 | import com.sourcegraph.common.CodyBundle
7 | import java.awt.GridBagConstraints
8 | import java.awt.GridBagLayout
9 | import javax.swing.JLabel
10 | import javax.swing.JPanel
11 | import javax.swing.JTextPane
12 | import javax.swing.text.SimpleAttributeSet
13 | import javax.swing.text.StyleConstants
14 |
15 | class ErrorPanel : JPanel(GridBagLayout()) {
16 | private val description =
17 | JTextPane().apply {
18 | text = CodyBundle.getString("ErrorPanel.content")
19 | foreground = SimpleTextAttributes.GRAY_ATTRIBUTES.fgColor
20 | val center = SimpleAttributeSet()
21 | StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER)
22 | styledDocument.setParagraphAttributes(0, styledDocument.length, center, false)
23 | }
24 |
25 | private val label =
26 | JLabel(CodyBundle.getString("ErrorPanel.label")).apply { icon = Icons.CodyLogoSlash }
27 |
28 | init {
29 | val constraints =
30 | GridBagConstraints().apply {
31 | fill = GridBagConstraints.HORIZONTAL
32 | gridx = 0
33 | insets = JBUI.insets(20)
34 | }
35 |
36 | add(label, constraints)
37 | add(description, constraints)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/common/CodyBundle.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.common
2 |
3 | import java.text.MessageFormat
4 | import java.util.*
5 | import org.jetbrains.annotations.PropertyKey
6 |
7 | object CodyBundle {
8 | private const val BUNDLE: String = "CodyBundle"
9 | private val instance: ResourceBundle = ResourceBundle.getBundle(BUNDLE)
10 |
11 | /**
12 | * A more restrictive version of [MessageFormat.format]. Since each parameter must be a non-null
13 | * [String], we can capture the unintended parameter types (like `io.vavr.control.Option`) more
14 | * easily during the build (this is realized with ArchUnit; see the test against `Option#toString`
15 | * in the top-level project). Note that we consciously use the name "fmt" instead of "format" to
16 | * avoid an accidental use of [String.format] and emphasize the need to use the
17 | * [lombok.experimental.ExtensionMethod] annotation.
18 | *
19 | * @param this@fmt as in [MessageFormat.format]
20 | * @param args as in [MessageFormat.format], but each parameter must be a non-null [String] and
21 | * not just a nullable [Object]
22 | * @return the formatted string
23 | */
24 | fun String.fmt(vararg args: String): String {
25 | return MessageFormat.format(this, *args)
26 | }
27 |
28 | fun getString(@PropertyKey(resourceBundle = BUNDLE) key: String): String {
29 | return instance.getString(key)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/config/CodyKeymapExtension.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.config
2 |
3 | import com.intellij.openapi.actionSystem.ActionGroup
4 | import com.intellij.openapi.actionSystem.ActionManager
5 | import com.intellij.openapi.actionSystem.AnAction
6 | import com.intellij.openapi.keymap.KeymapExtension
7 | import com.intellij.openapi.keymap.KeymapGroup
8 | import com.intellij.openapi.keymap.KeymapGroupFactory
9 | import com.intellij.openapi.keymap.impl.ui.ActionsTreeUtil
10 | import com.intellij.openapi.project.Project
11 | import com.intellij.openapi.util.Condition
12 | import com.sourcegraph.common.CodyBundle
13 |
14 | class CodyKeymapExtension : KeymapExtension {
15 | override fun createGroup(filtered: Condition?, project: Project?): KeymapGroup? {
16 | val result =
17 | KeymapGroupFactory.getInstance().createGroup(CodyBundle.getString("cody.plugin-name"))
18 | val actions = ActionsTreeUtil.getActions("Cody.AllActions").toList()
19 | actions.filterIsInstance().forEach { actionGroup ->
20 | val keymapGroup = KeymapGroupFactory.getInstance().createGroup(actionGroup.templateText)
21 | ActionsTreeUtil.getActions(ActionManager.getInstance().getId(actionGroup)).forEach {
22 | ActionsTreeUtil.addAction(keymapGroup, it, filtered, true)
23 | }
24 | result.addGroup(keymapGroup)
25 | }
26 |
27 | return result
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/cody/vscode/CancellationToken.java:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.vscode;
2 |
3 | import java.util.concurrent.CompletableFuture;
4 | import java.util.concurrent.ExecutionException;
5 | import java.util.function.Consumer;
6 |
7 | public class CancellationToken {
8 | private final CompletableFuture cancelled = new CompletableFuture<>();
9 |
10 | public boolean isDone() {
11 | return cancelled.isDone();
12 | }
13 |
14 | public void onCancellationRequested(Runnable callback) {
15 | onFinished(
16 | isCancelled -> {
17 | if (isCancelled) callback.run();
18 | });
19 | }
20 |
21 | public CompletableFuture onFinished(Consumer callback) {
22 | return this.cancelled.thenAccept(
23 | (isCancelled) -> {
24 | try {
25 | callback.accept(isCancelled);
26 | } catch (Exception ignored) {
27 | // Do nothing about exceptions in cancellation callbacks
28 | }
29 | });
30 | }
31 |
32 | public boolean isCancelled() {
33 | try {
34 | return this.cancelled.isDone() && this.cancelled.get();
35 | } catch (ExecutionException | InterruptedException ignored) {
36 | return true;
37 | }
38 | }
39 |
40 | public void dispose() {
41 | this.cancelled.complete(false);
42 | }
43 |
44 | public void abort() {
45 | this.cancelled.complete(true);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/agent/protocol_extensions/Position.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.agent.protocol_extensions
2 |
3 | // because line / column should probably be a
4 | // long
5 | import com.intellij.openapi.editor.Document
6 | import com.intellij.openapi.editor.LogicalPosition
7 | import com.sourcegraph.cody.agent.protocol_generated.Position
8 | import kotlin.math.max
9 | import kotlin.math.min
10 |
11 | fun Position(line: Int, character: Int): Position {
12 | return Position(line.toLong(), character.toLong())
13 | }
14 |
15 | fun Position.isOutsideOfDocument(document: Document): Boolean {
16 | return line < 0 || line > document.lineCount
17 | }
18 |
19 | fun Position.getRealLine(document: Document): Int {
20 | return max(0, min(max(0, document.lineCount - 1), line.toInt()))
21 | }
22 |
23 | fun Position.getRealColumn(document: Document): Int {
24 | val realLine = getRealLine(document)
25 | val lineLength = document.getLineEndOffset(realLine) - document.getLineStartOffset(realLine)
26 | return min(lineLength, character.toInt())
27 | }
28 |
29 | fun Position.toLogicalPosition(document: Document): LogicalPosition {
30 | return LogicalPosition(getRealLine(document), getRealColumn(document))
31 | }
32 |
33 | fun Position.toOffsetOrZero(document: Document): Int {
34 | val lineStartOffset = document.getLineStartOffset(getRealLine(document))
35 | return lineStartOffset + getRealColumn(document)
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/edit/lenses/actions/EditShowDiffAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.edit.lenses.actions
2 |
3 | import com.intellij.openapi.command.WriteCommandAction
4 | import com.intellij.openapi.editor.EditorFactory
5 | import com.sourcegraph.cody.agent.CodyAgentService
6 | import com.sourcegraph.cody.agent.protocol_extensions.toOffsetRange
7 | import com.sourcegraph.cody.agent.protocol_generated.EditTask_GetTaskDetailsParams
8 | import com.sourcegraph.common.ShowDocumentDiffAction
9 |
10 | class EditShowDiffAction :
11 | LensEditAction({ project, event, editor, taskId ->
12 | CodyAgentService.withAgent(project) { agent ->
13 | WriteCommandAction.runWriteCommandAction(project) {
14 | val editTask =
15 | agent.server.editTask_getTaskDetails(EditTask_GetTaskDetailsParams(taskId)).get()
16 | if (editTask != null) {
17 | val documentAfter = editor.document
18 | val documentBefore = EditorFactory.getInstance().createDocument(documentAfter.text)
19 | val (startOffset, endOffset) = editTask.selectionRange.toOffsetRange(documentBefore)
20 | documentBefore.replaceString(startOffset, endOffset, editTask.originalText ?: "")
21 | ShowDocumentDiffAction(documentBefore, documentAfter).actionPerformed(event)
22 | }
23 | }
24 | }
25 | }) {
26 | companion object {
27 | const val ID = "cody.fixup.codelens.diff"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/listeners/CodySelectionListener.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.listeners
2 |
3 | import com.intellij.openapi.editor.EditorKind
4 | import com.intellij.openapi.editor.event.SelectionEvent
5 | import com.intellij.openapi.editor.event.SelectionListener
6 | import com.intellij.openapi.project.Project
7 | import com.sourcegraph.cody.agent.CodyAgentService
8 | import com.sourcegraph.cody.agent.protocol_extensions.ProtocolTextDocumentExt
9 | import com.sourcegraph.cody.autocomplete.CodyAutocompleteManager
10 | import com.sourcegraph.config.ConfigUtil
11 |
12 | class CodySelectionListener(val project: Project) : SelectionListener {
13 | private val inlayManager = CodySelectionInlayManager(project)
14 |
15 | override fun selectionChanged(event: SelectionEvent) {
16 | if (!ConfigUtil.isCodyEnabled() ||
17 | event.editor == null ||
18 | event.editor.project != project ||
19 | event.editor.editorKind != EditorKind.MAIN_EDITOR) {
20 | return
21 | }
22 | val editor = event.editor
23 | ProtocolTextDocumentExt.fromEditorWithRangeSelection(editor, event)?.let { textDocument ->
24 | EditorChangesBus.documentChanged(project, textDocument)
25 | CodyAgentService.withAgent(project) { agent ->
26 | agent.server.textDocument_didChange(textDocument)
27 | }
28 | }
29 |
30 | CodyAutocompleteManager.instance.clearAutocompleteSuggestions(editor)
31 | inlayManager.handleSelectionChanged(editor, event)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/config/CodyWindowAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.config
2 |
3 | import com.intellij.openapi.project.Project
4 | import com.intellij.openapi.util.Disposer
5 | import com.intellij.openapi.wm.WindowManager
6 | import com.sourcegraph.cody.agent.CodyAgent
7 | import com.sourcegraph.cody.agent.CodyAgentService
8 | import com.sourcegraph.cody.agent.protocol_generated.Window_DidChangeFocusParams
9 | import java.awt.event.WindowAdapter
10 | import java.awt.event.WindowEvent
11 |
12 | class CodyWindowAdapter(private val project: Project) : WindowAdapter() {
13 |
14 | override fun windowActivated(e: WindowEvent?) {
15 | super.windowActivated(e)
16 | CodyAgentService.withAgent(project) { agent: CodyAgent ->
17 | agent.server.window_didChangeFocus(Window_DidChangeFocusParams(true))
18 | }
19 | }
20 |
21 | override fun windowDeactivated(e: WindowEvent?) {
22 | super.windowDeactivated(e)
23 | CodyAgentService.withAgent(project) { agent: CodyAgent ->
24 | agent.server.window_didChangeFocus(Window_DidChangeFocusParams(false))
25 | }
26 | }
27 |
28 | companion object {
29 | fun addWindowFocusListener(project: Project) {
30 | val frame = WindowManager.getInstance().getFrame(project)
31 | val listener = CodyWindowAdapter(project)
32 | frame?.addWindowListener(listener)
33 | Disposer.register(CodyAgentService.getInstance(project)) {
34 | frame?.removeWindowListener(listener)
35 | }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/.github/workflows/semgrep.yml:
--------------------------------------------------------------------------------
1 | name: Semgrep - SAST Scan
2 |
3 | on:
4 | pull_request_target:
5 | types: [ closed, edited, opened, synchronize, ready_for_review ]
6 |
7 | jobs:
8 | semgrep:
9 | permissions:
10 | contents: read # for actions/checkout to fetch code
11 | security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
12 | actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
13 | runs-on: ubuntu-latest
14 | container:
15 | image: returntocorp/semgrep
16 |
17 | steps:
18 | - uses: actions/checkout@v4
19 | with:
20 | ref: ${{ github.event.pull_request.head.ref }}
21 | repository: ${{ github.event.pull_request.head.repo.full_name }}
22 |
23 | - name: Checkout semgrep-rules repo
24 | uses: actions/checkout@v4
25 | with:
26 | repository: sourcegraph/security-semgrep-rules
27 | token: ${{ secrets.GH_SEMGREP_SAST_TOKEN }}
28 | path: semgrep-rules
29 |
30 | - name: Run Semgrep SAST Scan
31 | run: |
32 | mv semgrep-rules ../
33 | semgrep ci -f ../semgrep-rules/semgrep-rules/ --metrics=off --oss-only --suppress-errors --sarif -o results.sarif --exclude='semgrep-rules' --baseline-commit "$(git merge-base main HEAD)" || true
34 | - name: Upload SARIF file
35 | uses: github/codeql-action/upload-sarif@v3
36 | with:
37 | sarif_file: results.sarif
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/common/BrowserErrorNotification.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.common
2 |
3 | import com.intellij.notification.Notification
4 | import com.intellij.notification.NotificationType
5 | import com.intellij.notification.Notifications
6 | import com.intellij.openapi.actionSystem.AnAction
7 | import com.intellij.openapi.ide.CopyPasteManager
8 | import com.intellij.openapi.project.Project
9 | import com.sourcegraph.Icons
10 | import com.sourcegraph.common.ui.SimpleDumbAwareEDTAction
11 | import java.awt.datatransfer.StringSelection
12 | import java.net.URI
13 |
14 | object BrowserErrorNotification {
15 | fun show(project: Project?, uri: URI) {
16 | val notification =
17 | Notification(
18 | NotificationGroups.SOURCEGRAPH_ERRORS,
19 | "Sourcegraph",
20 | "Opening an external browser is not supported. You can still copy the URL to your clipboard and open it manually.",
21 | NotificationType.WARNING)
22 | val copyUrlAction: AnAction =
23 | SimpleDumbAwareEDTAction("Copy URL") {
24 | CopyPasteManager.getInstance().setContents(StringSelection(uri.toString()))
25 | notification.expire()
26 | }
27 | val dismissAction: AnAction = SimpleDumbAwareEDTAction("Dismiss") { notification.expire() }
28 | notification.setIcon(Icons.CodyLogo)
29 | notification.addAction(copyUrlAction)
30 | notification.addAction(dismissAction)
31 | Notifications.Bus.notify(notification)
32 | notification.notify(project)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/statusbar/CodyEnableLanguageForAutocompleteAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.statusbar
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent
4 | import com.sourcegraph.cody.config.CodyApplicationSettings
5 | import com.sourcegraph.common.ui.DumbAwareEDTAction
6 | import com.sourcegraph.config.ConfigUtil
7 | import com.sourcegraph.utils.CodyEditorUtil
8 | import com.sourcegraph.utils.CodyLanguageUtil
9 |
10 | class CodyEnableLanguageForAutocompleteAction : DumbAwareEDTAction() {
11 | override fun actionPerformed(e: AnActionEvent) {
12 | val applicationSettings = CodyApplicationSettings.instance
13 | applicationSettings.blacklistedLanguageIds =
14 | applicationSettings.blacklistedLanguageIds.filterNot {
15 | it == CodyEditorUtil.getLanguageForFocusedEditor(e)?.id
16 | }
17 | }
18 |
19 | override fun update(e: AnActionEvent) {
20 | super.update(e)
21 | val languageForFocusedEditor = CodyEditorUtil.getLanguageForFocusedEditor(e)
22 | val isLanguageBlacklisted =
23 | languageForFocusedEditor?.let { CodyLanguageUtil.isLanguageBlacklisted(it) } ?: false
24 | val languageName = languageForFocusedEditor?.displayName ?: ""
25 | e.presentation.isEnabledAndVisible =
26 | languageForFocusedEditor != null &&
27 | ConfigUtil.isCodyEnabled() &&
28 | ConfigUtil.isCodyAutocompleteEnabled() &&
29 | isLanguageBlacklisted
30 | e.presentation.text = "Enable Cody Autocomplete for $languageName"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # IntelliJ Platform Artifacts Repositories
2 | # -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html
3 | pluginGroup=com.sourcegraph.jetbrains
4 | pluginName=Cody: AI Coding Assistant with Autocomplete & Chat
5 | # SemVer format -> https://semver.org
6 | pluginVersion=6.0-localbuild
7 | # See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
8 | # for insight into build numbers and IntelliJ Platform versions.
9 | pluginSinceBuild=232
10 | pluginUntilBuild=243.*
11 | # IntelliJ Platform Properties -> https://github.com/JetBrains/gradle-intellij-plugin#intellij-platform-properties
12 | platformType=IC
13 | platformVersion=2023.2
14 | # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
15 | # Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22
16 | platformPlugins=Git4Idea,PerforceDirectPlugin,com.intellij.java
17 | javaVersion=17
18 | # Opt-out flag for bundling Kotlin standard library.
19 | # See https://plugins.jetbrains.com/docs/intellij/kotlin.html#kotlin-standard-library for details.
20 | # suppress inspection "UnusedProperty"
21 | kotlin.stdlib.default.dependency=false
22 | kotlin.daemon.jvmargs=-Xmx2g -Xms500m
23 | org.gradle.jvmargs=-Xmx4g -Xms500m
24 | # See https://docs.gradle.org/current/userguide/build_cache.html#sec:build_cache_configure
25 | nodeBinaries.commit=8755ae4c05fd476cd23f2972049111ba436c86d4
26 | nodeBinaries.version=v20.12.2
27 | cody.autocomplete.enableFormatting=true
28 | cody.commit=bb818530bd1200f6a1b26977d9f51ca38c04b3c1
29 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/vcs/RepoInfo.java:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.vcs;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 |
5 | public class RepoInfo {
6 | @NotNull public final VCSType vcsType;
7 |
8 | @NotNull
9 | public final String
10 | remoteUrl; // E.g. "git@github.com:sourcegraph/sourcegraph.git", with replacements already
11 |
12 | // applied
13 |
14 | @NotNull public final String remoteBranchName; // E.g. "main"
15 | @NotNull public final String relativePath; // E.g. "/client/jetbrains/package.json"
16 |
17 | public RepoInfo(
18 | @NotNull VCSType vcsType,
19 | @NotNull String remoteUrl,
20 | @NotNull String remoteBranchName,
21 | @NotNull String relativePath) {
22 | this.vcsType = vcsType;
23 | this.remoteUrl = remoteUrl;
24 | this.remoteBranchName = remoteBranchName;
25 | this.relativePath = relativePath;
26 | }
27 |
28 | // E.g. "sourcegraph/sourcegraph"
29 | @NotNull
30 | public String getRepoName() {
31 | int colonIndex = remoteUrl.lastIndexOf(":");
32 | int dotIndex = remoteUrl.lastIndexOf(".");
33 | return remoteUrl.substring(
34 | colonIndex + 1, (dotIndex == -1 || colonIndex > dotIndex) ? remoteUrl.length() : dotIndex);
35 | }
36 |
37 | // E.g. "github.com"
38 | @NotNull
39 | public String getCodeHostUrl() {
40 | int atIndex = remoteUrl.indexOf("@");
41 | int colonIndex = remoteUrl.lastIndexOf(":");
42 | return remoteUrl.substring(
43 | (atIndex == -1 && atIndex < colonIndex) ? 0 : atIndex + 1, colonIndex);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/agent/intellij_extensions/Document.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.agent.intellij_extensions
2 |
3 | import com.intellij.openapi.editor.Document
4 | import com.sourcegraph.cody.agent.protocol_extensions.Position
5 | import com.sourcegraph.cody.agent.protocol_generated.Position
6 | import com.sourcegraph.cody.agent.protocol_generated.Range
7 |
8 | fun Document.codyPosition(offset: Int): Position {
9 | val line = this.getLineNumber(offset)
10 | val lineStartOffset = this.getLineStartOffset(line)
11 | val character = offset - lineStartOffset
12 | return Position(line, character)
13 | }
14 |
15 | fun Document.codyRange(startOffset: Int, endOffset: Int): Range {
16 | if (startOffset < 0 ||
17 | startOffset > this.textLength ||
18 | endOffset > this.textLength ||
19 | startOffset > endOffset) {
20 | throw IllegalArgumentException(
21 | "codyRange error - startOffset: $startOffset, endOffset: $endOffset, textLength: ${this.textLength}")
22 | }
23 |
24 | val startLine = this.getLineNumber(startOffset)
25 | val lineStartOffset1 = this.getLineStartOffset(startLine)
26 | val startCharacter = startOffset - lineStartOffset1
27 |
28 | val endLine = this.getLineNumber(endOffset)
29 | val lineStartOffset2 =
30 | if (startLine == endLine) {
31 | lineStartOffset1
32 | } else {
33 | this.getLineStartOffset(endLine)
34 | }
35 | val endCharacter = endOffset - lineStartOffset2
36 |
37 | return Range(Position(startLine, startCharacter), Position(endLine, endCharacter))
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/agent/protocol/UriUtils.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.agent.protocol
2 |
3 | import com.google.gson.JsonDeserializationContext
4 | import com.google.gson.JsonDeserializer
5 | import com.google.gson.JsonElement
6 | import com.google.gson.JsonNull
7 | import com.google.gson.JsonObject
8 | import com.google.gson.JsonSerializer
9 | import java.lang.reflect.Type
10 | import java.net.URI
11 |
12 | val uriDeserializer =
13 | JsonDeserializer { jsonElement: JsonElement?, _: Type, _: JsonDeserializationContext ->
14 | fun asStringOrNull(elem: JsonElement?): String? {
15 | return if (elem == null || elem.isJsonNull) null else elem.asString
16 | }
17 |
18 | val j = jsonElement?.asJsonObject
19 | if (j == null || j.isJsonNull) {
20 | null
21 | } else if (j.isJsonPrimitive) {
22 | j.asString
23 | } else {
24 | URI(
25 | asStringOrNull(j["scheme"]),
26 | asStringOrNull(j["authority"]),
27 | asStringOrNull(j["path"]),
28 | asStringOrNull(j["query"]),
29 | asStringOrNull(j["fragment"]))
30 | }
31 | }
32 |
33 | val uriSerializer = JsonSerializer { uri: URI?, _, _ ->
34 | if (uri == null) {
35 | JsonNull.INSTANCE
36 | } else {
37 | val obj = JsonObject()
38 | obj.addProperty("scheme", uri.scheme)
39 | obj.addProperty("authority", uri.authority)
40 | obj.addProperty("path", uri.path)
41 | obj.addProperty("query", uri.query)
42 | obj.addProperty("fragment", uri.fragment)
43 | obj
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/chat/ui/MissingJcefPanel.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.chat.ui
2 |
3 | import com.intellij.openapi.projectRoots.impl.jdkDownloader.RuntimeChooserUtil
4 | import com.intellij.ui.SimpleTextAttributes
5 | import com.intellij.util.ui.JBUI
6 | import com.sourcegraph.common.CodyBundle
7 | import java.awt.GridBagConstraints
8 | import java.awt.GridBagLayout
9 | import javax.swing.JButton
10 | import javax.swing.JPanel
11 | import javax.swing.JTextPane
12 | import javax.swing.text.SimpleAttributeSet
13 | import javax.swing.text.StyleConstants
14 |
15 | class MissingJcefPanel : JPanel(GridBagLayout()) {
16 | private val jcefDescription =
17 | JTextPane().apply {
18 | text = CodyBundle.getString("MissingJcefPanel.content")
19 | foreground = SimpleTextAttributes.GRAY_ATTRIBUTES.fgColor
20 | val center = SimpleAttributeSet()
21 | StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER)
22 | styledDocument.setParagraphAttributes(0, styledDocument.length, center, false)
23 | }
24 |
25 | private val jcefButton =
26 | JButton(CodyBundle.getString("chooseRuntimeWithJcef.button")).apply {
27 | addActionListener { RuntimeChooserUtil.showRuntimeChooserPopup() }
28 | }
29 |
30 | init {
31 | val constraints =
32 | GridBagConstraints().apply {
33 | fill = GridBagConstraints.HORIZONTAL
34 | gridx = 0
35 | insets = JBUI.insets(20)
36 | }
37 |
38 | add(jcefDescription, constraints)
39 | add(jcefButton, constraints)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/autocomplete/render/InlayModelUtil.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.autocomplete.render
2 |
3 | import com.intellij.openapi.editor.Editor
4 | import com.intellij.openapi.editor.Inlay
5 | import com.intellij.openapi.editor.InlayModel
6 |
7 | object InlayModelUtil {
8 | @JvmStatic
9 | fun getAllInlays(inlayModel: InlayModel, startOffset: Int, endOffset: Int): List> {
10 | // can't use inlineModel.getInlineElementAt(caret.getVisualPosition()) here, as it
11 | // requires a write EDT thread;
12 | // we work around it by just looking at a range (potentially containing a single point)
13 | return listOf(
14 | inlayModel.getInlineElementsInRange(
15 | startOffset, endOffset, CodyAutocompleteElementRenderer::class.java),
16 | inlayModel.getBlockElementsInRange(
17 | startOffset, endOffset, CodyAutocompleteElementRenderer::class.java),
18 | inlayModel.getAfterLineEndElementsInRange(
19 | startOffset, endOffset, CodyAutocompleteElementRenderer::class.java))
20 | .flatten()
21 | }
22 |
23 | @JvmStatic
24 | fun getAllInlaysForEditor(editor: Editor): List> {
25 | val inlayModel =
26 | try {
27 | editor.inlayModel
28 | } catch (e: UnsupportedOperationException) {
29 | // Not all editors, for example ImaginaryEditor used in Intention Previews, support
30 | // inlays.
31 | return emptyList()
32 | }
33 | return getAllInlays(inlayModel, 0, editor.document.textLength)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/resources/icons/chat/llm/mistral.svg:
--------------------------------------------------------------------------------
1 |
32 |
--------------------------------------------------------------------------------
/features.json5:
--------------------------------------------------------------------------------
1 | {
2 | "features": [
3 | {
4 | "name": "NotebookBasedChatUI",
5 | "editors": {
6 | "jetbrains": {
7 | "status": "planned",
8 | }
9 | }
10 | },
11 | {
12 | "name": "Mixtral8x22BPreview",
13 | "editors": {
14 | "jetbrains": {
15 | "status": "planned",
16 | }
17 | }
18 | },
19 | {
20 | "name": "ToggleEnhancedContextButtons",
21 | "editors": {
22 | "jetbrains": {
23 | "status": "stable",
24 | }
25 | }
26 | },
27 | {
28 | "name": "GenerateUnitTestCodeAction",
29 | "editors": {
30 | "jetbrains": {
31 | "status": "planned",
32 | }
33 | },
34 | },
35 | {
36 | "name": "EditPreInstructions",
37 | "editors": {
38 | "jetbrains": {
39 | "status": "planned",
40 | }
41 | }
42 | },
43 | {
44 | "name": "EditShowWarningsOnLargeFiles",
45 | "editors": {
46 | "jetbrains": {
47 | "status": "stable",
48 | }
49 | }
50 | },
51 | {
52 | "name": "RightClickAddContext",
53 | "editors": {
54 | "jetbrains": {
55 | "status": "planned",
56 | }
57 | }
58 | },
59 | {
60 | "name": "ContextTokenCounter",
61 | "editors": {
62 | "jetbrains": {
63 | "status": "stable"
64 | }
65 | }
66 | },
67 | ],
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/auth/deprecated/DeprecatedCodyAccount.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.auth.deprecated
2 |
3 | import com.intellij.credentialStore.CredentialAttributes
4 | import com.intellij.credentialStore.generateServiceName
5 | import com.intellij.openapi.util.NlsSafe
6 | import com.intellij.util.xmlb.annotations.Attribute
7 | import com.intellij.util.xmlb.annotations.Property
8 | import com.intellij.util.xmlb.annotations.Tag
9 | import com.sourcegraph.cody.auth.SourcegraphServerPath
10 | import com.sourcegraph.config.ConfigUtil
11 | import java.io.File
12 | import java.util.UUID
13 |
14 | @Tag("account")
15 | data class DeprecatedCodyAccount(
16 | @NlsSafe @Attribute("name") var name: String = "",
17 | @Attribute("displayName") var displayName: String? = name,
18 | @Property(style = Property.Style.ATTRIBUTE, surroundWithTag = false)
19 | var server: SourcegraphServerPath = SourcegraphServerPath.from(ConfigUtil.DOTCOM_URL, ""),
20 | @Attribute("id") var id: String = generateId(),
21 | ) {
22 |
23 | fun credentialAttributes(): CredentialAttributes =
24 | CredentialAttributes(generateServiceName("Sourcegraph", id))
25 |
26 | override fun toString(): String = File(server.toString(), name).path
27 |
28 | override fun equals(other: Any?): Boolean {
29 | if (this === other) return true
30 | if (other !is DeprecatedCodyAccount) return false
31 | return id == other.id
32 | }
33 |
34 | override fun hashCode(): Int {
35 | return id.hashCode()
36 | }
37 |
38 | companion object {
39 | fun generateId() = UUID.randomUUID().toString()
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/agent/protocol_extensions/Range.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.agent.protocol_extensions
2 |
3 | import com.intellij.openapi.editor.Document
4 | import com.sourcegraph.cody.agent.protocol_generated.Range
5 |
6 | typealias RangePair = Pair
7 |
8 | typealias RangeOffset = Pair
9 |
10 | // We need to .plus(1) since the ranges use 0-based indexing
11 | // but IntelliJ presents it as 1-based indexing.
12 | public fun Range.intellijRange(): RangePair = RangePair(start.line.plus(1), end.line.plus(1))
13 |
14 | // The link to Sourcegraph Search on the other hand looks like this:
15 | fun Range.toSearchRange(): RangePair = RangePair(start.line.plus(1), end.line)
16 |
17 | /**
18 | * Converts the range represented by this [Range] object to a pair of offsets within the given
19 | * [Document].
20 | *
21 | * If the start or end position of the range is outside the document, the corresponding offset will
22 | * be set to 0 or the document's text length, respectively.
23 | *
24 | * @param document The [Document] to use for converting the range to offsets.
25 | * @return A [RangeOffset] pair containing the start and end offsets of the range within the
26 | * document.
27 | */
28 | fun Range.toOffsetRange(document: Document): RangeOffset {
29 | val startOffset = if (start.isOutsideOfDocument(document)) 0 else start.toOffsetOrZero(document)
30 | val endOffset =
31 | if (end.isOutsideOfDocument(document)) document.textLength else end.toOffsetOrZero(document)
32 |
33 | return RangeOffset(startOffset, endOffset)
34 | }
35 |
36 | fun Range.length() = end.line - start.line + 1
37 |
--------------------------------------------------------------------------------
/src/main/resources/icons/chat/llm/openai.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/src/integrationTest/kotlin/com/sourcegraph/cody/util/TestingCredentials.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.util
2 |
3 | import com.sourcegraph.config.ConfigUtil
4 |
5 | // See instructions in CONTRIBUTING.MD
6 | // for how to update the `redacted` tokens when the access token changes.
7 | data class TestingCredentials(
8 | val token: String?,
9 | val redactedToken: String,
10 | val serverEndpoint: String
11 | ) {
12 | companion object {
13 | val dotcom =
14 | TestingCredentials(
15 | token = System.getenv("SRC_DOTCOM_PRO_ACCESS_TOKEN"),
16 | redactedToken =
17 | "REDACTED_3dd704711f82a44ff6aba261b53b61a03fb8edba658774639148630d838c2d1d",
18 | serverEndpoint = ConfigUtil.DOTCOM_URL)
19 | val dotcomProUserRateLimited =
20 | TestingCredentials(
21 | token = System.getenv("SRC_DOTCOM_PRO_RATE_LIMIT_ACCESS_TOKEN"),
22 | redactedToken =
23 | "REDACTED_8c77b24d9f3d0e679509263c553887f2887d67d33c4e3544039c1889484644f5",
24 | serverEndpoint = ConfigUtil.DOTCOM_URL)
25 | val enterprise =
26 | TestingCredentials(
27 | token = System.getenv("SRC_ENTERPRISE_ACCESS_TOKEN"),
28 | redactedToken =
29 | "REDACTED_b20717265e7ab1d132874d8ff0be053ab9c1dacccec8dce0bbba76888b6a0a69",
30 | serverEndpoint = "https://demo.sourcegraph.com/")
31 | val s2 =
32 | TestingCredentials(
33 | token = System.getenv("SRC_S2_ACCESS_TOKEN"),
34 | redactedToken =
35 | "REDACTED_964f5256e709a8c5c151a63d8696d5c7ac81604d179405864d88ff48a9232364",
36 | serverEndpoint = "https://sourcegraph.sourcegraph.com/")
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/flake.lock:
--------------------------------------------------------------------------------
1 | {
2 | "nodes": {
3 | "flake-utils": {
4 | "inputs": {
5 | "systems": "systems"
6 | },
7 | "locked": {
8 | "lastModified": 1692799911,
9 | "narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=",
10 | "owner": "numtide",
11 | "repo": "flake-utils",
12 | "rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44",
13 | "type": "github"
14 | },
15 | "original": {
16 | "owner": "numtide",
17 | "repo": "flake-utils",
18 | "type": "github"
19 | }
20 | },
21 | "nixpkgs": {
22 | "locked": {
23 | "lastModified": 1693355128,
24 | "narHash": "sha256-+ZoAny3ZxLcfMaUoLVgL9Ywb/57wP+EtsdNGuXUJrwg=",
25 | "owner": "NixOS",
26 | "repo": "nixpkgs",
27 | "rev": "a63a64b593dcf2fe05f7c5d666eb395950f36bc9",
28 | "type": "github"
29 | },
30 | "original": {
31 | "owner": "NixOS",
32 | "ref": "nixpkgs-unstable",
33 | "repo": "nixpkgs",
34 | "type": "github"
35 | }
36 | },
37 | "root": {
38 | "inputs": {
39 | "flake-utils": "flake-utils",
40 | "nixpkgs": "nixpkgs"
41 | }
42 | },
43 | "systems": {
44 | "locked": {
45 | "lastModified": 1681028828,
46 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
47 | "owner": "nix-systems",
48 | "repo": "default",
49 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
50 | "type": "github"
51 | },
52 | "original": {
53 | "owner": "nix-systems",
54 | "repo": "default",
55 | "type": "github"
56 | }
57 | }
58 | },
59 | "root": "root",
60 | "version": 7
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/find/browser/SourcegraphJBCefBrowser.java:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.find.browser;
2 |
3 | import com.intellij.openapi.util.Disposer;
4 | import com.intellij.ui.jcef.JBCefBrowser;
5 | import com.sourcegraph.cody.config.notification.CodySettingChangeListener;
6 | import com.sourcegraph.config.ThemeUtil;
7 | import javax.swing.*;
8 | import org.cef.CefApp;
9 | import org.jetbrains.annotations.NotNull;
10 |
11 | public class SourcegraphJBCefBrowser extends JBCefBrowser {
12 | private final JavaToJSBridge javaToJSBridge;
13 |
14 | public SourcegraphJBCefBrowser(@NotNull JSToJavaBridgeRequestHandler requestHandler) {
15 | super("http://sourcegraph/html/index.html");
16 | // Create and set up JCEF browser
17 | CefApp.getInstance()
18 | .registerSchemeHandlerFactory("http", "sourcegraph", new HttpSchemeHandlerFactory());
19 |
20 | // Create bridges, set up handlers, then run init function
21 | String initJSCode = "window.initializeSourcegraph();";
22 | JSToJavaBridge jsToJavaBridge = new JSToJavaBridge(this, requestHandler, initJSCode);
23 | Disposer.register(this, jsToJavaBridge);
24 | javaToJSBridge = new JavaToJSBridge(this);
25 |
26 | requestHandler
27 | .getProject()
28 | .getService(CodySettingChangeListener.class)
29 | .setJavaToJSBridge(javaToJSBridge);
30 |
31 | UIManager.addPropertyChangeListener(
32 | propertyChangeEvent -> {
33 | if (propertyChangeEvent.getPropertyName().equals("lookAndFeel")) {
34 | javaToJSBridge.callJS("themeChanged", ThemeUtil.getCurrentThemeAsJson());
35 | }
36 | });
37 | }
38 |
39 | @NotNull
40 | public JavaToJSBridge getJavaToJSBridge() {
41 | return javaToJSBridge;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/statusbar/RateLimitErrorWarningAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.statusbar
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent
4 | import com.intellij.openapi.ui.Messages
5 | import com.sourcegraph.cody.Icons
6 | import com.sourcegraph.cody.telemetry.TelemetryV2
7 | import com.sourcegraph.common.BrowserOpener
8 | import com.sourcegraph.common.ui.DumbAwareEDTAction
9 | import com.sourcegraph.config.ConfigUtil
10 |
11 | class RateLimitErrorWarningAction(
12 | actionText: String,
13 | private val dialogContent: String,
14 | private val dialogTitle: String,
15 | private val shouldShowUpgradeOption: Boolean
16 | ) : DumbAwareEDTAction(actionText) {
17 | override fun actionPerformed(e: AnActionEvent) {
18 |
19 | val actions =
20 | if (shouldShowUpgradeOption) {
21 | arrayOf("Close", "Upgrade")
22 | } else {
23 | arrayOf("Ok")
24 | }
25 |
26 | val result =
27 | Messages.showDialog(
28 | e.project,
29 | dialogContent,
30 | dialogTitle,
31 | actions,
32 | /* defaultOptionIndex= */ 1,
33 | Icons.CodyLogo)
34 |
35 | val feature =
36 | if (shouldShowUpgradeOption) "upsellUsageLimitStatusBar" else "abuseUsageLimitStatusBar"
37 | e.project?.let { TelemetryV2.sendTelemetryEvent(it, feature, "shown") }
38 |
39 | if (result == 1) {
40 | e.project?.let { TelemetryV2.sendTelemetryEvent(it, "upsellUsageLimitStatusBar", "clicked") }
41 | BrowserOpener.openInBrowser(e.project, "https://sourcegraph.com/cody/subscription")
42 | }
43 | }
44 |
45 | override fun update(e: AnActionEvent) {
46 | super.update(e)
47 | e.presentation.isEnabledAndVisible = ConfigUtil.isCodyEnabled()
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/jetbrains_feedback.yml:
--------------------------------------------------------------------------------
1 | name: JetBrains Feedback ፨
2 | description: "File feedback for any of the JetBrains IDEs: IntelliJ, Goland, WebStorm, etc."
3 | title: "feedback: "
4 | labels:
5 | - team/jetbrains
6 | projects:
7 | - sourcegraph/381
8 | body:
9 | - type: markdown
10 | attributes:
11 | value: |
12 | Thanks for taking the time to share your feedback with us! If you'd like to report a bug, please use the [JetBrains Bug report template](https://github.com/sourcegraph/jetbrains/issues/new/choose) instead.
13 |
14 | Tip: You can attach images or videos by dragging it into the text box.
15 | - type: textarea
16 | attributes:
17 | label: Installation Information
18 | description: Trigger the action "About", click on "Copy and close" and paste the output here
19 | validations:
20 | required: true
21 | - type: textarea
22 | attributes:
23 | label: Share your feedback
24 | description: Let us know how we can keep improving Cody for JetBrains. If relevant, please include steps on how to reproduce behaviour.
25 | validations:
26 | required: true
27 | - type: textarea
28 | attributes:
29 | label: Additional context (logs, images, etc)
30 | description: |
31 | Please add any links, images, or references that can give us more context around your feedback.
32 |
33 | For logs - Trigger the action "Show Log", open the file, search for exceptions related to Cody/Sourcegraph and copy relevant lines here
34 | Alternatively, feel free to upload idea.log as an attachment but please make sure it doesn't contain sensitive information (it normally doesn't)
35 |
36 | Tip: You can attach images or videos by dragging it into the text box.
37 | validations:
38 | required: false
39 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/statusbar/CodyDisableLanguageForAutocompleteAction.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.statusbar
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent
4 | import com.sourcegraph.cody.auth.CodyAccount
5 | import com.sourcegraph.cody.autocomplete.CodyAutocompleteManager
6 | import com.sourcegraph.cody.config.CodyApplicationSettings
7 | import com.sourcegraph.common.ui.DumbAwareEDTAction
8 | import com.sourcegraph.config.ConfigUtil
9 | import com.sourcegraph.utils.CodyEditorUtil
10 | import com.sourcegraph.utils.CodyLanguageUtil
11 |
12 | class CodyDisableLanguageForAutocompleteAction : DumbAwareEDTAction() {
13 | override fun actionPerformed(e: AnActionEvent) {
14 | val applicationSettings = CodyApplicationSettings.instance
15 | CodyEditorUtil.getLanguageForFocusedEditor(e)?.id?.let { languageId ->
16 | applicationSettings.blacklistedLanguageIds =
17 | applicationSettings.blacklistedLanguageIds.plus(languageId)
18 | CodyAutocompleteManager.instance.clearAutocompleteSuggestionsForLanguageId(languageId)
19 | }
20 | }
21 |
22 | override fun update(e: AnActionEvent) {
23 | super.update(e)
24 | val languageForFocusedEditor = CodyEditorUtil.getLanguageForFocusedEditor(e)
25 | val isLanguageBlacklisted =
26 | languageForFocusedEditor?.let { CodyLanguageUtil.isLanguageBlacklisted(it) } ?: false
27 | val languageName = languageForFocusedEditor?.displayName ?: ""
28 | e.presentation.isEnabledAndVisible =
29 | languageForFocusedEditor != null &&
30 | ConfigUtil.isCodyEnabled() &&
31 | ConfigUtil.isCodyAutocompleteEnabled() &&
32 | !isLanguageBlacklisted &&
33 | CodyAccount.hasActiveAccount()
34 | e.presentation.text = "Disable Cody Autocomplete for $languageName"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/listeners/CodyCaretListener.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.listeners
2 |
3 | import com.intellij.openapi.command.CommandProcessor
4 | import com.intellij.openapi.editor.EditorKind
5 | import com.intellij.openapi.editor.event.CaretEvent
6 | import com.intellij.openapi.editor.event.CaretListener
7 | import com.intellij.openapi.project.Project
8 | import com.sourcegraph.cody.agent.CodyAgent
9 | import com.sourcegraph.cody.agent.CodyAgentService
10 | import com.sourcegraph.cody.agent.protocol_extensions.ProtocolTextDocumentExt
11 | import com.sourcegraph.cody.autocomplete.CodyAutocompleteManager
12 | import com.sourcegraph.cody.vscode.InlineCompletionTriggerKind
13 | import com.sourcegraph.config.ConfigUtil
14 | import com.sourcegraph.utils.CodyEditorUtil
15 |
16 | class CodyCaretListener(val project: Project) : CaretListener {
17 | override fun caretPositionChanged(e: CaretEvent) {
18 | if (!ConfigUtil.isCodyEnabled() ||
19 | e.editor.editorKind != EditorKind.MAIN_EDITOR ||
20 | e.editor.project != project) {
21 | return
22 | }
23 |
24 | val commandName = CommandProcessor.getInstance().currentCommandName
25 | if (commandName == CodyEditorUtil.VIM_EXIT_INSERT_MODE_ACTION) {
26 | return
27 | }
28 |
29 | ProtocolTextDocumentExt.fromEditorWithOffsetSelection(e.editor, e)?.let { textDocument ->
30 | EditorChangesBus.documentChanged(project, textDocument)
31 | CodyAgentService.withAgent(project) { agent: CodyAgent ->
32 | agent.server.textDocument_didChange(textDocument)
33 | }
34 | }
35 |
36 | CodyAutocompleteManager.instance.clearAutocompleteSuggestions(e.editor)
37 | CodyAutocompleteManager.instance.triggerAutocomplete(
38 | e.editor, e.editor.caretModel.offset, InlineCompletionTriggerKind.AUTOMATIC)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/vcs/ConvertUtil.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.vcs
2 |
3 | import java.net.URI
4 |
5 | data class CodebaseName(val value: String)
6 |
7 | fun convertGitCloneURLToCodebaseNameOrError(theCloneURL: String): CodebaseName {
8 | val cloneURL = theCloneURL.lowercase()
9 |
10 | // Handle common Git SSH URL format
11 | val sshUrlRegexMatchResult = Regex("""^[\w-]+@([^:]+):(?:(\d+)/)?([\w-/.]+)$""").find(cloneURL)
12 | if (sshUrlRegexMatchResult != null) {
13 | val (host, port, path) = sshUrlRegexMatchResult.destructured
14 | return CodebaseName(
15 | "${host}${if (port.isNotEmpty()) ":$port" else ""}/${path.removeSuffix(".git")}")
16 | }
17 |
18 | var uri = URI(cloneURL)
19 | if (uri.scheme == null) {
20 | uri = URI("http://$cloneURL")
21 | }
22 |
23 | // Handle Azure DevOps URLs
24 | if (uri.host?.contains("dev.azure") == true && !uri.path.isNullOrEmpty()) {
25 | return CodebaseName("${uri.host}${uri.path.replace("/_git", "")}")
26 | }
27 |
28 | // Handle GitHub URLs
29 | if (uri.scheme?.startsWith("github") == true) {
30 | return CodebaseName("github.com/${uri.schemeSpecificPart.replace(".git", "")}")
31 | }
32 |
33 | // Handle GitLab URLs
34 | if (uri.scheme?.startsWith("gitlab") == true) {
35 | return CodebaseName("gitlab.com/${uri.schemeSpecificPart.replace(".git", "")}")
36 | }
37 |
38 | // Handle HTTPS URLs
39 | if (uri.scheme?.startsWith("http") == true &&
40 | !uri.host.isNullOrEmpty() &&
41 | !uri.path.isNullOrEmpty()) {
42 | return CodebaseName("${uri.host}${uri.path?.replace(".git", "")}")
43 | }
44 |
45 | // Generic URL
46 | if (uri.host != null && !uri.path.isNullOrEmpty()) {
47 | return CodebaseName("${uri.host}${uri.path.replace(".git", "")}")
48 | }
49 |
50 | throw Exception("Cody could not extract repo name from clone URL $cloneURL")
51 | }
52 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/sourcegraph/cody/agent/protocol/UriUtilsTest.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.agent.protocol
2 |
3 | import com.google.gson.Gson
4 | import com.google.gson.GsonBuilder
5 | import com.intellij.openapi.util.SystemInfoRt
6 | import com.intellij.testFramework.fixtures.BasePlatformTestCase
7 | import java.net.URI
8 |
9 | class UriUtilsTest : BasePlatformTestCase() {
10 | fun `test uri serialization and deserialization`() {
11 | val gson: Gson =
12 | GsonBuilder()
13 | .registerTypeAdapter(URI::class.java, uriDeserializer)
14 | .registerTypeAdapter(URI::class.java, uriSerializer)
15 | .serializeNulls()
16 | .create()
17 |
18 | fun roundtripConversion(path: String) =
19 | gson.fromJson(gson.toJson(URI.create(path)), URI::class.java).toString()
20 |
21 | if (SystemInfoRt.isWindows) {
22 | assertEquals("file:/c:/a/b/c/d.java", roundtripConversion("file:///c:/a/b/c/d.java"))
23 | assertEquals("file://c:/a/b/c/d.java", roundtripConversion("file://c:/a/b/c/d.java"))
24 | assertEquals("file:/c:/a/b/c/d.java?#", roundtripConversion("file:///c:/a/b/c/d.java?#"))
25 | assertEquals("file://c:/a/b/c/d.java?#", roundtripConversion("file://c:/a/b/c/d.java?#"))
26 | assertEquals("/c:/a/b/c/d.java", roundtripConversion("/c:/a/b/c/d.java"))
27 | assertEquals("c:/a/b/c/d.java", roundtripConversion("c:/a/b/c/d.java"))
28 | assertEquals("c:/a/b/c/d.java?#", roundtripConversion("c:/a/b/c/d.java?#"))
29 | assertEquals("/c:/a/b/c/d.java?#", roundtripConversion("/c:/a/b/c/d.java?#"))
30 | } else {
31 | assertEquals("/a/b/c/d.java", roundtripConversion("/a/b/c/d.java"))
32 | assertEquals("/a/b/c/d.java?#", roundtripConversion("/a/b/c/d.java?#"))
33 | assertEquals("file:/a/b/c/d.java", roundtripConversion("file:///a/b/c/d.java"))
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/sourcegraph/cody/Icons.java:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody;
2 |
3 | import com.intellij.openapi.util.IconLoader;
4 | import com.intellij.ui.AnimatedIcon;
5 | import javax.swing.*;
6 |
7 | public interface Icons {
8 | Icon CodyLogo = IconLoader.getIcon("/icons/codyLogo.svg", Icons.class);
9 |
10 | interface Actions {
11 | Icon Add = IconLoader.getIcon("/icons/actions/huge_plus.svg", Icons.class);
12 | Icon Edit = IconLoader.getIcon("/icons/actions/pencil.svg", Icons.class);
13 | Icon Hide = IconLoader.getIcon("/icons/actions/hide.svg", Icons.class);
14 | Icon Send = IconLoader.getIcon("/icons/actions/send.svg", Icons.class);
15 | Icon DisabledSend = IconLoader.getIcon("/icons/actions/disabledSend.svg", Icons.class);
16 | }
17 |
18 | interface StatusBar {
19 | Icon CompletionInProgress = AnimatedIcon.Default.INSTANCE;
20 | Icon CodyAvailable = IconLoader.getIcon("/icons/codyLogoMonochromatic.svg", Icons.class);
21 | Icon CodyAutocompleteDisabled =
22 | IconLoader.getIcon("/icons/cody-logo-heavy-slash.svg", Icons.class);
23 |
24 | Icon CodyUnavailable =
25 | IconLoader.getIcon("/icons/codyLogoMonochromaticUnavailable.svg", Icons.class);
26 | }
27 |
28 | interface Edit {
29 | Icon Error = IconLoader.getIcon("/icons/edit/error.svg", Icons.class);
30 | }
31 |
32 | interface LLM {
33 | Icon Anthropic = IconLoader.getIcon("/icons/chat/llm/anthropic.svg", Icons.class);
34 | Icon Google = IconLoader.getIcon("/icons/chat/llm/google.svg", Icons.class);
35 | Icon OpenAI = IconLoader.getIcon("/icons/chat/llm/openai.svg", Icons.class);
36 | Icon Mistral = IconLoader.getIcon("/icons/chat/llm/mistral.svg", Icons.class);
37 | Icon Ollama = IconLoader.getIcon("/icons/chat/llm/ollama.svg", Icons.class);
38 | Icon ProSticker = IconLoader.getIcon("/icons/chat/llm/pro_sticker.svg", Icons.class);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/sourcegraph/cody/agent/ProtocolCompatibilityTest.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.agent
2 |
3 | import com.intellij.testFramework.fixtures.BasePlatformTestCase
4 | import com.sourcegraph.cody.agent.protocol_generated.CodyAgentServer as TargetCodyAgentServer
5 | import kotlin.reflect.full.declaredFunctions
6 | import kotlin.test.assertTrue
7 | import org.junit.Test
8 | import org.junit.runner.RunWith
9 | import org.junit.runners.JUnit4
10 |
11 | @RunWith(JUnit4::class)
12 | class ProtocolCompatibilityTest : BasePlatformTestCase() {
13 | /**
14 | * I verified this works by altering one of the copied methods. interface
15 | * com.sourcegraph.cody.agent._SubsetGeneratedCodyAgentServer is not a subset of interface
16 | * com.sourcegraph.cody.agent.protocol_generated.CodyAgentServer. Incompatible methods:
17 | * (graphql_currentUserId, [kotlin.String]) This ensures we make no changes to the protocol while
18 | * we're still subsetting generated protocol methods.
19 | */
20 | private fun assertSubsetInterface(superInterface: Class<*>, subInterface: Class<*>) {
21 | val superMethods =
22 | superInterface.kotlin.declaredFunctions
23 | .map { it.name to it.parameters.drop(1).map { param -> param.type } }
24 | .toSet()
25 | val subMethods =
26 | subInterface.kotlin.declaredFunctions
27 | .map { it.name to it.parameters.drop(1).map { param -> param.type } }
28 | .toSet()
29 |
30 | assertTrue(
31 | subMethods.all { it in superMethods },
32 | "$subInterface is not a subset of $superInterface. Incompatible methods: \n${(subMethods - superMethods).joinToString("\n")}")
33 | }
34 |
35 | @Test
36 | fun `copies generated protocol verbatim`() {
37 | assertSubsetInterface(
38 | TargetCodyAgentServer::class.java, _SubsetGeneratedCodyAgentServer::class.java)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/sourcegraph/cody/autocomplete/action/AcceptAutocompleteActionHandler.kt:
--------------------------------------------------------------------------------
1 | package com.sourcegraph.cody.autocomplete.action
2 |
3 | import com.intellij.openapi.actionSystem.DataContext
4 | import com.intellij.openapi.application.WriteAction
5 | import com.intellij.openapi.editor.Caret
6 | import com.intellij.openapi.editor.Editor
7 | import com.intellij.openapi.editor.ScrollType
8 | import com.sourcegraph.cody.agent.protocol_generated.AutocompleteItem
9 | import com.sourcegraph.utils.CodyEditorUtil
10 |
11 | class AcceptAutocompleteActionHandler : AutocompleteActionHandler() {
12 | /**
13 | * Applies the autocomplete to the document at a caret: 1. Replaces the string between the caret
14 | * offset and its line end with the current completion 2. Moves the caret to the start and end
15 | * offsets with the completion text. If there are multiple carets, uses the first one. If there
16 | * are no completions at the caret, does nothing.
17 | */
18 | override fun doExecute(editor: Editor, maybeCaret: Caret?, dataContext: DataContext?) {
19 | val caret = maybeCaret ?: getSingleCaret(editor) ?: return
20 | val completionItem = getCurrentAutocompleteItem(caret) ?: return
21 |
22 | AcceptCodyAutocompleteAction.tracker.set(completionItem.id)
23 | WriteAction.run { applyInsertText(editor, caret, completionItem) }
24 | }
25 |
26 | companion object {
27 |
28 | private fun applyInsertText(editor: Editor, caret: Caret, completionItem: AutocompleteItem) {
29 | val document = editor.document
30 | val range = CodyEditorUtil.getTextRange(document, completionItem.range)
31 | document.replaceString(range.startOffset, range.endOffset, completionItem.insertText)
32 | caret.moveToOffset(range.startOffset + completionItem.insertText.length)
33 | editor.scrollingModel.scrollToCaret(ScrollType.MAKE_VISIBLE)
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------