├── scripts ├── .gitignore ├── react-shim.js ├── package.json ├── buffer-shim.js ├── process-shim.js ├── verify-release.sh ├── install-ldid.sh ├── tsconfig.json ├── version-from-git-tag.sh ├── copy-protocol.sh └── next-release.sh ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ └── jetbrains_feedback.yml ├── workflows │ ├── backport.yml │ ├── stable-release.yml │ ├── nightly-release.yml │ ├── experimental-release.yml │ └── semgrep.yml └── PULL_REQUEST_TEMPLATE.md ├── src ├── integrationTest │ ├── resources │ │ └── testProjects │ │ │ └── documentCode │ │ │ ├── .gitignore │ │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── Foo.java │ └── kotlin │ │ └── com │ │ └── sourcegraph │ │ └── cody │ │ ├── AllSuites.kt │ │ ├── util │ │ ├── CustomJunitClassRunner.kt │ │ ├── RepeatableSuite.kt │ │ └── TestingCredentials.kt │ │ └── NonEdtIdeaTestExecutionPolicy.kt ├── main │ ├── resources │ │ ├── META-INF │ │ │ ├── plugin-git.xml │ │ │ ├── plugin-perforce.xml │ │ │ └── pluginIcon.svg │ │ ├── graphql │ │ │ └── query │ │ │ │ └── getUserDetails.graphql │ │ ├── icons │ │ │ ├── actions │ │ │ │ ├── send.svg │ │ │ │ ├── send_dark.svg │ │ │ │ ├── disabledSend.svg │ │ │ │ ├── disabledSend_dark.svg │ │ │ │ ├── huge_plus.svg │ │ │ │ ├── pencil.svg │ │ │ │ ├── huge_plus_dark.svg │ │ │ │ ├── pencil_dark.svg │ │ │ │ ├── hide.svg │ │ │ │ └── hide_dark.svg │ │ │ ├── repo-ignored.svg │ │ │ ├── repo-ignored_dark.svg │ │ │ ├── repo-host-bitbucket.svg │ │ │ ├── repo-host-bitbucket_dark.svg │ │ │ ├── chat │ │ │ │ ├── newChat.svg │ │ │ │ ├── newChat_dark.svg │ │ │ │ ├── llm │ │ │ │ │ ├── anthropic.svg │ │ │ │ │ ├── google.svg │ │ │ │ │ ├── mistral.svg │ │ │ │ │ └── openai.svg │ │ │ │ └── chat_command.svg │ │ │ ├── edit │ │ │ │ ├── error.svg │ │ │ │ ├── edit_code.svg │ │ │ │ └── document_code.svg │ │ │ ├── repo-host-gitlab.svg │ │ │ ├── repo-host-gitlab_dark.svg │ │ │ ├── repo-host-generic.svg │ │ │ ├── repo-host-generic_dark.svg │ │ │ ├── repo-host-github.svg │ │ │ ├── repo-host-github_dark.svg │ │ │ ├── sourcegraphLogo.svg │ │ │ ├── codyLogo.svg │ │ │ ├── gearPlain.svg │ │ │ └── gearPlain_dark.svg │ │ └── html │ │ │ └── index.html │ ├── kotlin │ │ └── com │ │ │ └── sourcegraph │ │ │ ├── cody │ │ │ ├── autocomplete │ │ │ │ ├── action │ │ │ │ │ ├── CodyAction.kt │ │ │ │ │ ├── TriggerAutocompleteAction.kt │ │ │ │ │ ├── DisposeInlaysAction.kt │ │ │ │ │ ├── CycleForwardAutocompleteAction.kt │ │ │ │ │ ├── CycleBackwardAutocompleteAction.kt │ │ │ │ │ ├── DisposeInlaysActionHandler.kt │ │ │ │ │ ├── AcceptCodyAutocompleteAction.kt │ │ │ │ │ ├── CodyActionPromoter.kt │ │ │ │ │ ├── TriggerAutocompleteActionHandler.kt │ │ │ │ │ └── AcceptAutocompleteActionHandler.kt │ │ │ │ └── render │ │ │ │ │ ├── AutocompleteRendererType.kt │ │ │ │ │ ├── CodyAutocompleteSingleLineRenderer.kt │ │ │ │ │ └── InlayModelUtil.kt │ │ │ ├── agent │ │ │ │ ├── protocol │ │ │ │ │ ├── Repo.kt │ │ │ │ │ ├── NetworkRequest.kt │ │ │ │ │ ├── ChatModelsParams.kt │ │ │ │ │ ├── package-info.java │ │ │ │ │ ├── GetFeatureFlag.kt │ │ │ │ │ ├── ErrorCode.kt │ │ │ │ │ ├── Webview.kt │ │ │ │ │ ├── RateLimitError.kt │ │ │ │ │ └── UriUtils.kt │ │ │ │ ├── protocol_extensions │ │ │ │ │ ├── Util.kt │ │ │ │ │ ├── BillingMetadata.kt │ │ │ │ │ ├── CurrentUserCodySubscription.kt │ │ │ │ │ ├── ModelUtil.kt │ │ │ │ │ ├── Position.kt │ │ │ │ │ └── Range.kt │ │ │ │ ├── action │ │ │ │ │ └── CodyAgentRestartAction.kt │ │ │ │ ├── CodyConnectionTimeoutExceptionNotification.kt │ │ │ │ └── intellij_extensions │ │ │ │ │ └── Document.kt │ │ │ ├── api │ │ │ │ ├── SourcegraphGQLQueryLoader.kt │ │ │ │ ├── SourcegraphStatusCodeException.kt │ │ │ │ ├── SourcegraphGQLQueries.kt │ │ │ │ ├── SourcegraphJsonException.kt │ │ │ │ ├── SourcegraphAuthenticationException.kt │ │ │ │ ├── GraphQLFileNotFoundException.kt │ │ │ │ ├── SourcegraphApiResponse.kt │ │ │ │ ├── SourcegraphConfusingException.kt │ │ │ │ └── SourcegraphApiRequests.kt │ │ │ ├── config │ │ │ │ ├── SourcegraphParseException.kt │ │ │ │ ├── notification │ │ │ │ │ ├── CodySettingChangeActionNotifier.kt │ │ │ │ │ ├── ChangeListener.kt │ │ │ │ │ └── CodySettingChangeContext.kt │ │ │ │ ├── ui │ │ │ │ │ ├── UpdateChannel.kt │ │ │ │ │ └── lang │ │ │ │ │ │ ├── LanguageEntryColumn.kt │ │ │ │ │ │ ├── LanguageNameCellRenderer.kt │ │ │ │ │ │ ├── LanguageCheckboxColumn.kt │ │ │ │ │ │ ├── LanguageEntry.kt │ │ │ │ │ │ └── AutocompleteLanguageTableWrapper.kt │ │ │ │ ├── migration │ │ │ │ │ └── AccountsMigration.kt │ │ │ │ ├── SettingsModel.kt │ │ │ │ ├── actions │ │ │ │ │ └── EnableOffScreenRenderingAction.kt │ │ │ │ ├── CodySettingsFileChangeListener.kt │ │ │ │ ├── CodyKeymapExtension.kt │ │ │ │ └── CodyWindowAdapter.kt │ │ │ ├── initialization │ │ │ │ ├── Activity.kt │ │ │ │ └── PrettyTimer.kt │ │ │ ├── chat │ │ │ │ ├── actions │ │ │ │ │ ├── SmellCommand.kt │ │ │ │ │ ├── ExplainCommand.kt │ │ │ │ │ ├── ExportChatsAction.kt │ │ │ │ │ └── NewChatAction.kt │ │ │ │ ├── ui │ │ │ │ │ ├── Pluralize.kt │ │ │ │ │ ├── ErrorPanel.kt │ │ │ │ │ └── MissingJcefPanel.kt │ │ │ │ ├── OpenChatAction.kt │ │ │ │ └── PromptHistory.kt │ │ │ ├── commands │ │ │ │ └── CommandId.kt │ │ │ ├── OpenWebviewDevToolsAction.kt │ │ │ ├── edit │ │ │ │ ├── lenses │ │ │ │ │ ├── actions │ │ │ │ │ │ ├── EditUndoAction.kt │ │ │ │ │ │ ├── EditAcceptAction.kt │ │ │ │ │ │ ├── EditCancelAction.kt │ │ │ │ │ │ ├── EditRetryAction.kt │ │ │ │ │ │ └── EditShowDiffAction.kt │ │ │ │ │ ├── EditCodeVisionGroupSettingProvider.kt │ │ │ │ │ └── providers │ │ │ │ │ │ ├── EditDiffCodeVisionProvider.kt │ │ │ │ │ │ ├── EditWorkingCodeVisionProvider.kt │ │ │ │ │ │ ├── EditRetryCodeVisionProvider.kt │ │ │ │ │ │ ├── EditUndoCodeVisionProvider.kt │ │ │ │ │ │ ├── EditCancelCodeVisionProvider.kt │ │ │ │ │ │ └── EditAcceptCodeVisionProvider.kt │ │ │ │ ├── CodyActionPrompter.kt │ │ │ │ ├── actions │ │ │ │ │ ├── BaseEditCodeActionHandler.kt │ │ │ │ │ ├── DocumentCodeAction.kt │ │ │ │ │ ├── TestCodeAction.kt │ │ │ │ │ └── EditCodeAction.kt │ │ │ │ ├── InlineEditPromptEditCodeAction.kt │ │ │ │ └── InstructionsInputTextArea.kt │ │ │ ├── statusbar │ │ │ │ ├── ReportCodyBugAction.kt │ │ │ │ ├── CodyOpenSettingsAction.kt │ │ │ │ ├── CodyEnableAutocompleteAction.kt │ │ │ │ ├── CodyWidgetFactory.kt │ │ │ │ ├── CodyDisableAutocompleteAction.kt │ │ │ │ ├── OpenLogAction.kt │ │ │ │ ├── CodyEnableLanguageForAutocompleteAction.kt │ │ │ │ ├── RateLimitErrorWarningAction.kt │ │ │ │ └── CodyDisableLanguageForAutocompleteAction.kt │ │ │ ├── history │ │ │ │ ├── state │ │ │ │ │ ├── EnhancedContextState.kt │ │ │ │ │ ├── RemoteRepositoryState.kt │ │ │ │ │ ├── MessageState.kt │ │ │ │ │ ├── AccountData.kt │ │ │ │ │ ├── HistoryState.kt │ │ │ │ │ ├── ChatState.kt │ │ │ │ │ └── LLMState.kt │ │ │ │ └── HistoryService.kt │ │ │ ├── listeners │ │ │ │ ├── EditorChangesBus.kt │ │ │ │ ├── CodyFocusChangeListener.kt │ │ │ │ ├── CodySelectionListener.kt │ │ │ │ └── CodyCaretListener.kt │ │ │ ├── internals │ │ │ │ ├── InternalsStatusBarActionGroup.kt │ │ │ │ └── InternalsStatusBarWidgetFactory.kt │ │ │ ├── editor │ │ │ │ └── CommandListener.kt │ │ │ ├── ui │ │ │ │ └── web │ │ │ │ │ ├── WebPanelTabTitleProvider.kt │ │ │ │ │ └── WebPanelFileType.kt │ │ │ └── auth │ │ │ │ └── deprecated │ │ │ │ ├── DeprecatedCodyPersistentAccounts.kt │ │ │ │ └── DeprecatedCodyAccount.kt │ │ │ ├── common │ │ │ ├── RegexEscaper.kt │ │ │ ├── NotificationGroups.kt │ │ │ ├── ui │ │ │ │ └── DumbAwareEDTAction.kt │ │ │ ├── ErrorNotification.kt │ │ │ ├── BrowserOpener.kt │ │ │ ├── CodyBundle.kt │ │ │ └── BrowserErrorNotification.kt │ │ │ └── utils │ │ │ ├── CollectionUtil.kt │ │ │ ├── ThreadingUtil.kt │ │ │ ├── CodyLanguageUtil.kt │ │ │ └── CodyProjectUtil.kt │ └── java │ │ └── com │ │ └── sourcegraph │ │ ├── cody │ │ ├── agent │ │ │ ├── WebviewCreateParams.kt │ │ │ ├── protocol │ │ │ │ └── package-info.java │ │ │ ├── CodyAgentException.java │ │ │ ├── ConfigFeaturesObserver.java │ │ │ └── WebviewPostMessageParams.kt │ │ ├── autocomplete │ │ │ ├── package-info.java │ │ │ └── AutocompleteProviderType.java │ │ ├── vscode │ │ │ ├── InlineCompletionTriggerKind.java │ │ │ ├── package-info.java │ │ │ ├── TextDocument.java │ │ │ └── CancellationToken.java │ │ ├── CodyActionGroup.java │ │ └── Icons.java │ │ ├── vcs │ │ ├── VCSType.java │ │ ├── RevisionContext.java │ │ ├── RepoInfo.java │ │ └── ConvertUtil.kt │ │ ├── website │ │ ├── OpenFileAction.java │ │ ├── SearchSelectionAction.java │ │ ├── SearchRepositoryAction.java │ │ └── CopyAction.java │ │ ├── find │ │ ├── browser │ │ │ ├── HttpSchemeHandlerFactory.java │ │ │ └── SourcegraphJBCefBrowser.java │ │ ├── OpenFindAction.java │ │ ├── Search.java │ │ ├── HeaderPanel.java │ │ └── SourcegraphVirtualFile.java │ │ ├── Icons.java │ │ └── config │ │ └── GoToPluginSettingsButtonFactory.java ├── intellij2023 │ └── kotlin │ │ └── com │ │ └── intellij │ │ └── codeInsight │ │ └── inline │ │ └── completion │ │ ├── InlineCompletionProviderID.kt │ │ ├── elements │ │ ├── InlineCompletionGrayTextElement.kt │ │ └── InlineCompletionElement.kt │ │ └── suggestion │ │ └── InlineCompletionSuggestion.kt └── test │ └── kotlin │ └── com │ └── sourcegraph │ └── cody │ ├── autocomplete │ └── render │ │ └── InlayModelUtilTest.kt │ ├── agent │ ├── protocol │ │ ├── extensions.kt │ │ └── UriUtilsTest.kt │ └── ProtocolCompatibilityTest.kt │ └── config │ └── SourcegraphServerPathTest.kt ├── .tool-versions ├── docs ├── keymaps.png ├── infilling_autocomplete.png ├── multiline_autocomplete.png ├── single_line_autocomplete.png └── cycle_through_autocomplete.gif ├── libs └── ActionUpdateThread.jar ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── settings.gradle.kts ├── .stylelintrc.json ├── globals.d.ts ├── CONTRIBUTING.md ├── .gitignore ├── flake.nix ├── gradle.properties ├── features.json5 └── flake.lock /scripts/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | -------------------------------------------------------------------------------- /src/integrationTest/resources/testProjects/documentCode/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | java adoptopenjdk-17.0.12+7 2 | nodejs 20.4.0 3 | pnpm 8.6.7 4 | -------------------------------------------------------------------------------- /scripts/react-shim.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | export { React } 4 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/plugin-git.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/plugin-perforce.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /docs/keymaps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcegraph/jetbrains/HEAD/docs/keymaps.png -------------------------------------------------------------------------------- /libs/ActionUpdateThread.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcegraph/jetbrains/HEAD/libs/ActionUpdateThread.jar -------------------------------------------------------------------------------- /docs/infilling_autocomplete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcegraph/jetbrains/HEAD/docs/infilling_autocomplete.png -------------------------------------------------------------------------------- /docs/multiline_autocomplete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcegraph/jetbrains/HEAD/docs/multiline_autocomplete.png -------------------------------------------------------------------------------- /docs/single_line_autocomplete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcegraph/jetbrains/HEAD/docs/single_line_autocomplete.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcegraph/jetbrains/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /docs/cycle_through_autocomplete.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcegraph/jetbrains/HEAD/docs/cycle_through_autocomplete.gif -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/autocomplete/action/CodyAction.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.autocomplete.action 2 | 3 | interface CodyAction 4 | -------------------------------------------------------------------------------- /src/main/java/com/sourcegraph/cody/agent/WebviewCreateParams.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.agent 2 | 3 | data class WebviewCreateParams(val id: String) 4 | -------------------------------------------------------------------------------- /src/main/java/com/sourcegraph/vcs/VCSType.java: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.vcs; 2 | 3 | public enum VCSType { 4 | GIT, 5 | PERFORCE, 6 | UNKNOWN 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/sourcegraph/cody/autocomplete/package-info.java: -------------------------------------------------------------------------------- 1 | /** Logic related to inline code completions. */ 2 | package com.sourcegraph.cody.autocomplete; 3 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/agent/protocol/Repo.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.agent.protocol 2 | 3 | data class Repo(val name: String, val id: String) 4 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/api/SourcegraphGQLQueryLoader.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.api 2 | 3 | object SourcegraphGQLQueryLoader : CachingGraphQLQueryLoader() 4 | -------------------------------------------------------------------------------- /src/main/resources/graphql/query/getUserDetails.graphql: -------------------------------------------------------------------------------- 1 | query { 2 | currentUser { 3 | id 4 | username 5 | displayName 6 | avatarURL 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/config/SourcegraphParseException.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.config 2 | 3 | class SourcegraphParseException(message: String) : RuntimeException(message) 4 | -------------------------------------------------------------------------------- /src/main/java/com/sourcegraph/cody/vscode/InlineCompletionTriggerKind.java: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.vscode; 2 | 3 | public enum InlineCompletionTriggerKind { 4 | INVOKE, 5 | AUTOMATIC 6 | } 7 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/agent/protocol/NetworkRequest.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.agent.protocol 2 | 3 | data class NetworkRequest(val url: String?, val body: String?, val error: String?) 4 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/agent/protocol/ChatModelsParams.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.agent.protocol 2 | 3 | enum class ModelUsage(val value: String) { 4 | CHAT("chat"), 5 | EDIT("edit") 6 | } 7 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/api/SourcegraphStatusCodeException.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.api 2 | 3 | class SourcegraphStatusCodeException(message: String?) : SourcegraphConfusingException(message) 4 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/api/SourcegraphGQLQueries.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.api 2 | 3 | object SourcegraphGQLQueries { 4 | const val getUserDetails = "graphql/query/getUserDetails.graphql" 5 | } 6 | -------------------------------------------------------------------------------- /src/intellij2023/kotlin/com/intellij/codeInsight/inline/completion/InlineCompletionProviderID.kt: -------------------------------------------------------------------------------- 1 | package com.intellij.codeInsight.inline.completion 2 | 3 | @JvmInline value class InlineCompletionProviderID(val id: String) 4 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/api/SourcegraphJsonException.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.api 2 | 3 | class SourcegraphJsonException(message: String, cause: Throwable) : 4 | SourcegraphConfusingException(message, cause) 5 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/autocomplete/render/AutocompleteRendererType.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.autocomplete.render 2 | 3 | enum class AutocompleteRendererType { 4 | INLINE, 5 | BLOCK, 6 | AFTER_LINE_END 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/send.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/api/SourcegraphAuthenticationException.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.api 2 | 3 | import java.io.IOException 4 | 5 | class SourcegraphAuthenticationException(message: String) : IOException(message) 6 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/initialization/Activity.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.initialization 2 | 3 | import com.intellij.openapi.project.Project 4 | 5 | interface Activity { 6 | fun runActivity(project: Project) 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/send_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/disabledSend.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /scripts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "canhaz": "ts-node canhaz.ts" 4 | }, 5 | "type": "commonjs", 6 | "devDependencies": { 7 | "@types/node": "^22.7.2", 8 | "ts-node": "^10.9.2", 9 | "typescript": "^5.6.2" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/api/GraphQLFileNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.api 2 | 3 | import java.io.FileNotFoundException 4 | 5 | class GraphQLFileNotFoundException(message: String) : FileNotFoundException(message) 6 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/disabledSend_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /scripts/buffer-shim.js: -------------------------------------------------------------------------------- 1 | // This file is used for esbuild's `inject` option 2 | // in order to load node polyfills in the webworker 3 | // extension host. 4 | // See: https://esbuild.github.io/api/#inject. 5 | export const Buffer = require('buffer/').Buffer 6 | -------------------------------------------------------------------------------- /scripts/process-shim.js: -------------------------------------------------------------------------------- 1 | // This file is used for esbuild's `inject` option 2 | // in order to load node polyfills in the webworker 3 | // extension host. 4 | // See: https://esbuild.github.io/api/#inject. 5 | export const process = require('process/browser') 6 | -------------------------------------------------------------------------------- /src/main/java/com/sourcegraph/cody/vscode/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Rough line-by-line translation of VS Code APIs into Java with implementations that use the 3 | * IntelliJ SDK instead of the VS Code API. 4 | */ 5 | package com.sourcegraph.cody.vscode; 6 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "Sourcegraph" 2 | 3 | plugins { id("org.gradle.toolchains.foojay-resolver-convention") version ("0.4.0") } 4 | 5 | val isCiServer = System.getenv().containsKey("CI") 6 | 7 | buildCache { local { isEnabled = !isCiServer } } 8 | -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.stylelintrc.json"], 3 | "overrides": [ 4 | { 5 | "files": ["./webview/src/index.scss"], 6 | "rules": { 7 | "@sourcegraph/filenames-match-regex": null 8 | } 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/chat/actions/SmellCommand.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.chat.actions 2 | 3 | import com.sourcegraph.cody.commands.CommandId 4 | 5 | class SmellCommand : BaseCommandAction() { 6 | 7 | override val myCommandId = CommandId.Smell 8 | } 9 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/commands/CommandId.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.commands 2 | 3 | enum class CommandId(val id: String, val displayName: String) { 4 | Explain("cody.command.Explain", "Explain Code"), 5 | Smell("cody.command.Smell", "Smell Code"), 6 | } 7 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/chat/actions/ExplainCommand.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.chat.actions 2 | 3 | import com.sourcegraph.cody.commands.CommandId 4 | 5 | class ExplainCommand : BaseCommandAction() { 6 | 7 | override val myCommandId = CommandId.Explain 8 | } 9 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/agent/protocol_extensions/Util.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.agent.protocol_extensions 2 | 3 | inline fun > String.toEnumIgnoreCase(): T? { 4 | return enumValues().firstOrNull { it.name.equals(this, ignoreCase = true) } 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/sourcegraph/cody/agent/protocol/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Handwritten classes for the agent JSON-RPC protocol. 3 | * 4 | *

In the future, these classes should ideally be replaced with automatically generated classes. 5 | */ 6 | package com.sourcegraph.cody.agent.protocol; 7 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/agent/protocol/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @deprecated Replaced by {@link package com.sourcegraph.cody.agent.generated_protocol} and {@link package com.sourcegraph.cody.agent.protocol_extensions} 3 | */ 4 | @Deprecated 5 | package com.sourcegraph.cody.agent.protocol; -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/autocomplete/action/TriggerAutocompleteAction.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.autocomplete.action 2 | 3 | import com.intellij.openapi.editor.actionSystem.EditorAction 4 | 5 | class TriggerAutocompleteAction : EditorAction(TriggerAutocompleteActionHandler()), CodyAction 6 | -------------------------------------------------------------------------------- /src/main/resources/icons/repo-ignored.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/main/resources/icons/repo-ignored_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /globals.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.scss' { 2 | const cssModule: string 3 | export default cssModule 4 | } 5 | declare module '*.css' { 6 | const cssModule: string 7 | export default cssModule 8 | } 9 | 10 | /** 11 | * Set by shared/dev/jest-environment.js 12 | */ 13 | declare var jsdom: import('jsdom').JSDOM 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Sourcegraph JetBrains Plugin 2 | 3 | Thank you for your interest in contributing to Sourcegraph! 4 | Sourcegraph JetBrains development has moved to 5 | https://github.com/sourcegraph/cody . See [the JetBrains contributing 6 | guide](https://github.com/sourcegraph/cody/blob/main/jetbrains/CONTRIBUTING.md) there. -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/chat/ui/Pluralize.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.chat.ui 2 | 3 | // Can pluralize "file", "line", "repo" and "repository" 4 | fun String.pluralize(count: Int): String = 5 | when { 6 | count == 1 -> this 7 | this.endsWith("y") -> this.dropLast(1) + "ies" 8 | else -> this + "s" 9 | } 10 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/agent/protocol_extensions/BillingMetadata.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.agent.protocol_extensions 2 | 3 | object BillingMetadata { 4 | object Product { 5 | const val CODY = "cody" 6 | } 7 | 8 | object Category { 9 | const val CORE = "core" 10 | const val BILLABLE = "billable" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/integrationTest/kotlin/com/sourcegraph/cody/AllSuites.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody 2 | 3 | import com.sourcegraph.cody.edit.DocumentCodeTest 4 | import com.sourcegraph.cody.util.RepeatableSuite 5 | import org.junit.runner.RunWith 6 | import org.junit.runners.Suite 7 | 8 | @RunWith(RepeatableSuite::class) @Suite.SuiteClasses(DocumentCodeTest::class) class AllSuites 9 | -------------------------------------------------------------------------------- /src/main/resources/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Sourcegraph 4 | 5 | 6 | 7 | 8 | 9 |

10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/resources/icons/repo-host-bitbucket.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/intellij2023/kotlin/com/intellij/codeInsight/inline/completion/elements/InlineCompletionGrayTextElement.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 | class InlineCompletionGrayTextElement(val text: String) : InlineCompletionElement 6 | -------------------------------------------------------------------------------- /src/main/resources/icons/repo-host-bitbucket_dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/common/RegexEscaper.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.common 2 | 3 | import java.util.regex.Pattern 4 | 5 | object RegexEscaper { 6 | private val SPECIAL_REGEX_CHARS = Pattern.compile("[{}()\\[\\].+*?^$\\\\|]")!! 7 | 8 | fun escapeRegexChars(string: String): String { 9 | return SPECIAL_REGEX_CHARS.matcher(string).replaceAll("\\\\$0") 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/utils/CollectionUtil.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.utils 2 | 3 | class CollectionUtil { 4 | companion object { 5 | infix fun List.sameElements(anotherList: List) = 6 | this.size == anotherList.size && this.toSet() == anotherList.toSet() 7 | 8 | infix fun List.diff(anotherList: List) = this.minus(anotherList.toSet()) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/autocomplete/action/DisposeInlaysAction.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.autocomplete.action 2 | 3 | import com.intellij.openapi.editor.actionSystem.EditorAction 4 | import com.intellij.openapi.project.DumbAware 5 | 6 | class DisposeInlaysAction : EditorAction(DisposeInlaysActionHandler()), DumbAware, CodyAction { 7 | init { 8 | setInjectedContext(true) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/agent/protocol/GetFeatureFlag.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.agent.protocol 2 | 3 | import com.sourcegraph.cody.agent.protocol_generated.FeatureFlags_GetFeatureFlagParams 4 | 5 | object GetFeatureFlag { 6 | val UseSscForCodySubscription = FeatureFlags_GetFeatureFlagParams("UseSscForCodySubscription") 7 | val CodyProTrialEnded = FeatureFlags_GetFeatureFlagParams("CodyProTrialEnded") 8 | } 9 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/common/NotificationGroups.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.common 2 | 3 | object NotificationGroups { 4 | const val CODY_AUTH = "cody.auth" 5 | const val SOURCEGRAPH_ERRORS = "Sourcegraph errors" 6 | const val SOURCEGRAPH_URL_SHARING = "Sourcegraph: URL sharing" 7 | const val CODY_UPDATES = "Sourcegraph Cody + Code Search plugin updates" 8 | const val TOOLWINDOW = "Sourcegraph Cody" 9 | } 10 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/agent/protocol_extensions/CurrentUserCodySubscription.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.agent.protocol_extensions 2 | 3 | import com.sourcegraph.cody.agent.protocol_generated.CurrentUserCodySubscription 4 | 5 | fun CurrentUserCodySubscription.isProPlan(): Boolean { 6 | return plan == "PRO" 7 | } 8 | 9 | fun CurrentUserCodySubscription.isPendingStatus(): Boolean { 10 | return status == "PENDING" 11 | } 12 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/autocomplete/action/CycleForwardAutocompleteAction.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.autocomplete.action 2 | 3 | import com.intellij.openapi.editor.actionSystem.EditorAction 4 | import com.sourcegraph.cody.autocomplete.action.CycleCodyAutocompleteActionHandler.Companion.CycleDirection 5 | 6 | class CycleForwardAutocompleteAction : 7 | EditorAction(CycleCodyAutocompleteActionHandler(CycleDirection.FORWARD)), CodyAction 8 | -------------------------------------------------------------------------------- /src/main/resources/icons/chat/newChat.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/autocomplete/action/CycleBackwardAutocompleteAction.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.autocomplete.action 2 | 3 | import com.intellij.openapi.editor.actionSystem.EditorAction 4 | import com.sourcegraph.cody.autocomplete.action.CycleCodyAutocompleteActionHandler.Companion.CycleDirection 5 | 6 | class CycleBackwardAutocompleteAction : 7 | EditorAction(CycleCodyAutocompleteActionHandler(CycleDirection.BACKWARD)), CodyAction 8 | -------------------------------------------------------------------------------- /src/main/resources/icons/chat/newChat_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /scripts/verify-release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eu 3 | 4 | echo "=====================================================" 5 | echo "= Running automated tests before publishing release =" 6 | echo "=====================================================" 7 | set -x 8 | unset CODY_DIR 9 | unset SKIP_CODE_SEARCH_BUILD 10 | 11 | ./gradlew clean || ./gradlew clean # Run it twice because Gradle clean is brittle 12 | ./gradlew buildPlugin 13 | ./gradlew verifyPlugin 14 | -------------------------------------------------------------------------------- /src/main/kotlin/com/sourcegraph/cody/OpenWebviewDevToolsAction.kt: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent 4 | import com.sourcegraph.common.ui.DumbAwareEDTAction 5 | 6 | class OpenWebviewDevToolsAction(val toolWindowContent: CodyToolWindowContent) : 7 | DumbAwareEDTAction("Open WebView DevTools") { 8 | override fun actionPerformed(e: AnActionEvent) { 9 | toolWindowContent.openDevTools() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/huge_plus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/pencil.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/huge_plus_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/pencil_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/main/java/com/sourcegraph/website/OpenFileAction.java: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.website; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.sourcegraph.common.BrowserOpener; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | public class OpenFileAction extends FileActionBase { 8 | @Override 9 | protected void handleFileUri(@NotNull Project project, @NotNull String url) { 10 | BrowserOpener.INSTANCE.openInBrowser(project, url); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /scripts/install-ldid.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Script to install `ldid2` on Linux computers to codesign the macos-arm64 binary for the agent. 4 | 5 | set -eux 6 | 7 | # Check if ldid is installed 8 | if command -v ldid &>/dev/null; then 9 | echo "ldid is already installed." 10 | exit 0 11 | fi 12 | 13 | curl -Lo ldid.zip https://github.com/xerub/ldid/archive/refs/heads/master.zip 14 | unzip ldid.zip 15 | cd ldid-master 16 | ./make.sh 17 | cp ldid /usr/local/bin/ 18 | -------------------------------------------------------------------------------- /src/main/java/com/sourcegraph/website/SearchSelectionAction.java: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.website; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | @SuppressWarnings("MissingActionUpdateThread") 7 | public class SearchSelectionAction extends SearchActionBase { 8 | @Override 9 | public void actionPerformed(@NotNull AnActionEvent event) { 10 | super.actionPerformedMode(event, Scope.ANYWHERE); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/sourcegraph/cody/agent/CodyAgentException.java: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.agent; 2 | 3 | public class CodyAgentException extends Exception { 4 | public CodyAgentException(String message) { 5 | super(message); 6 | } 7 | 8 | public CodyAgentException(String message, Exception e) { 9 | super(message, e); 10 | } 11 | 12 | @Override 13 | public Throwable fillInStackTrace() { 14 | // don't fill in stack trace 15 | return this; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/sourcegraph/website/SearchRepositoryAction.java: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.website; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | @SuppressWarnings("MissingActionUpdateThread") 7 | public class SearchRepositoryAction extends SearchActionBase { 8 | @Override 9 | public void actionPerformed(@NotNull AnActionEvent event) { 10 | super.actionPerformedMode(event, Scope.REPOSITORY); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /scripts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "skipLibCheck": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "outDir": "./dist", 10 | "rootDir": ".", 11 | "moduleResolution": "node", 12 | "baseUrl": ".", 13 | "paths": { 14 | "*": ["node_modules/*"] 15 | } 16 | }, 17 | "include": ["canhaz.ts"], 18 | "exclude": ["node_modules"] 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/sourcegraph/cody/vscode/TextDocument.java: -------------------------------------------------------------------------------- 1 | package com.sourcegraph.cody.vscode; 2 | 3 | import com.sourcegraph.cody.agent.protocol_generated.Position; 4 | import java.net.URI; 5 | import java.util.Optional; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | public interface TextDocument { 9 | URI uri(); 10 | 11 | @NotNull 12 | String fileName(); 13 | 14 | String getText(); 15 | 16 | Position positionAt(int offset); 17 | 18 | @NotNull 19 | Optional 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 | 10 | 11 | 12 | 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 | 2 | 3 | 4 | 5 | 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 | 2 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 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 | 2 | 3 | 4 | 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 | 3 | 4 | -------------------------------------------------------------------------------- /src/main/resources/icons/chat/chat_command.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/icons/actions/hide_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /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 | 2 | 3 | 4 | 5 | 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 | 5 | 11 | 12 | 13 | 15 | 16 | 17 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 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 | 5 | 11 | 12 | 13 | 15 | 16 | 17 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 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 | 3 | 4 | 5 | 6 | 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 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/icons/gearPlain_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 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 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 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 | 10 | 11 | 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 | --------------------------------------------------------------------------------