├── .gitignore ├── gradle.properties ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src └── main │ ├── resources │ ├── icons │ │ └── icon.png │ └── META-INF │ │ ├── plugin.xml │ │ └── pluginIcon.svg │ └── kotlin │ └── dev │ └── koding │ └── copilot │ ├── const.kt │ ├── completion │ ├── CopilotWeigher.kt │ ├── CopilotPrefixMatcher.kt │ ├── api │ │ └── CompletionData.kt │ └── CopilotCompletionContributor.kt │ ├── config │ ├── ApplicationSettings.kt │ ├── ApplicationConfigurable.kt │ └── ApplicationConfigurable.form │ ├── util │ └── Notifications.kt │ └── auth │ └── OAuthHandler.kt ├── .github └── workflows │ └── build.yml ├── README.MD ├── gradlew.bat └── gradlew /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'GitHubCopilot' 2 | 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KodingDev/JetBrainsCopilot/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KodingDev/JetBrainsCopilot/HEAD/src/main/resources/icons/icon.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/koding/copilot/const.kt: -------------------------------------------------------------------------------- 1 | package dev.koding.copilot 2 | 3 | import com.intellij.openapi.util.IconLoader 4 | import io.ktor.client.* 5 | import io.ktor.client.features.json.* 6 | 7 | val httpClient = HttpClient { 8 | install(JsonFeature) { 9 | serializer = GsonSerializer() 10 | } 11 | } 12 | 13 | val copilotIcon = IconLoader.findIcon("/icons/icon.png") -------------------------------------------------------------------------------- /src/main/kotlin/dev/koding/copilot/completion/CopilotWeigher.kt: -------------------------------------------------------------------------------- 1 | package dev.koding.copilot.completion 2 | 3 | import com.intellij.codeInsight.lookup.LookupElement 4 | import com.intellij.codeInsight.lookup.LookupElementWeigher 5 | import dev.koding.copilot.completion.api.CompletionChoice 6 | 7 | class CopilotWeigher : LookupElementWeigher("CopilotLookupElementWeigher", false, true) { 8 | 9 | override fun weigh(element: LookupElement) = 10 | if (element.`object` is CompletionChoice) Int.MIN_VALUE else Int.MAX_VALUE 11 | 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/dev/koding/copilot/completion/CopilotPrefixMatcher.kt: -------------------------------------------------------------------------------- 1 | package dev.koding.copilot.completion 2 | 3 | import com.intellij.codeInsight.completion.PrefixMatcher 4 | import com.intellij.codeInsight.lookup.LookupElement 5 | import com.intellij.codeInsight.lookup.LookupElementDecorator 6 | import dev.koding.copilot.completion.api.CompletionChoice 7 | 8 | class CopilotPrefixMatcher(private val inner: PrefixMatcher) : PrefixMatcher(inner.prefix) { 9 | override fun prefixMatches(element: LookupElement): Boolean { 10 | if (element.`object` is CompletionChoice) return true 11 | else if (element is LookupElementDecorator<*>) return prefixMatches(element.delegate) 12 | return super.prefixMatches(element) 13 | } 14 | 15 | override fun isStartMatch(element: LookupElement?): Boolean { 16 | if (element?.`object` is CompletionChoice) return true 17 | return super.isStartMatch(element) 18 | } 19 | 20 | override fun prefixMatches(name: String) = inner.prefixMatches(name) 21 | override fun cloneWithPrefix(prefix: String) = CopilotPrefixMatcher(inner.cloneWithPrefix(prefix)) 22 | } -------------------------------------------------------------------------------- /src/main/kotlin/dev/koding/copilot/config/ApplicationSettings.kt: -------------------------------------------------------------------------------- 1 | package dev.koding.copilot.config 2 | 3 | import com.intellij.openapi.components.PersistentStateComponent 4 | import com.intellij.openapi.components.State 5 | import com.intellij.openapi.components.Storage 6 | import com.intellij.openapi.components.service 7 | 8 | val settings: ApplicationSettings 9 | get() = service() 10 | 11 | @State(name = "GitHubCopilotSettings", storages = [Storage("copilot.xml")]) 12 | class ApplicationSettings : PersistentStateComponent { 13 | 14 | data class State( 15 | var token: String? = null, 16 | var contentLines: Int = 15 17 | ) 18 | 19 | private var state = State() 20 | 21 | // TODO: Change this to delegation 22 | var token: String? 23 | get() = state.token 24 | set(value) = value.let { state.token = it } 25 | 26 | var contentLines: Int 27 | get() = state.contentLines 28 | set(value) = value.let { state.contentLines = it } 29 | 30 | override fun getState() = state 31 | override fun loadState(state: State) = state.let { this.state = it } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | dev.koding.GitHubCopilot 3 | GitHub Copilot 4 | Koding Dev 5 | 6 | IS NOT an official product of GitHub and is meant for specialized use only. 9 | ]]> 10 | 11 | com.intellij.modules.lang 12 | 13 | 14 | 15 | 16 | 20 | 21 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/koding/copilot/util/Notifications.kt: -------------------------------------------------------------------------------- 1 | package dev.koding.copilot.util 2 | 3 | import com.intellij.notification.NotificationGroupManager 4 | import com.intellij.notification.NotificationType 5 | import com.intellij.openapi.actionSystem.AnAction 6 | import com.intellij.openapi.actionSystem.AnActionEvent 7 | 8 | object Notifications { 9 | 10 | private val group = NotificationGroupManager.getInstance().getNotificationGroup("GitHub Copilot") 11 | private var shown = mutableSetOf() 12 | 13 | @Suppress("DialogTitleCapitalization") 14 | fun send( 15 | message: String, 16 | type: NotificationType = NotificationType.INFORMATION, 17 | once: Boolean = false, 18 | vararg actions: NotificationAction 19 | ) { 20 | if (once && message in shown) return 21 | group.createNotification(message, type) 22 | .apply { 23 | actions.forEach { 24 | addAction(object : AnAction(it.name) { 25 | override fun actionPerformed(e: AnActionEvent) = it.action() 26 | }) 27 | } 28 | shown += message 29 | }.notify(null) 30 | } 31 | 32 | data class NotificationAction( 33 | val name: String, 34 | val action: () -> Unit 35 | ) 36 | } -------------------------------------------------------------------------------- /src/main/kotlin/dev/koding/copilot/completion/api/CompletionData.kt: -------------------------------------------------------------------------------- 1 | package dev.koding.copilot.completion.api 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import dev.koding.copilot.httpClient 5 | import io.ktor.client.request.* 6 | 7 | data class CompletionResponse( 8 | val choices: List 9 | ) 10 | 11 | data class CompletionChoice( 12 | val text: String 13 | ) 14 | 15 | data class CompletionRequest( 16 | val prompt: String, 17 | @SerializedName("max_tokens") 18 | val maxTokens: Int = 70, 19 | val temperature: Double = 0.2, 20 | @SerializedName("top_p") 21 | val topP: Double = 1.0, 22 | @SerializedName("n") 23 | val count: Int = 3, 24 | @SerializedName("logprobs") 25 | val logProbability: Int = 2, 26 | val stop: List = listOf("\n") 27 | ) { 28 | suspend fun send(token: String): CompletionResponse = 29 | httpClient.post("https://copilot.githubassets.com/v1/engines/github-multi-stochbpe-cushman-pii/completions") { 30 | header("Authorization", "Bearer $token") 31 | header("Content-Type", "application/json") 32 | header("Accept", "application/json") 33 | header("Openai-Organization", "github-copilot") 34 | header("OpenAI-Intent", "copilot-ghost") 35 | 36 | body = this@CompletionRequest 37 | } 38 | } -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | workflow_dispatch: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Set up JDK 11 15 | uses: actions/setup-java@v2 16 | with: 17 | java-version: '16' 18 | distribution: 'adopt' 19 | - name: Cache Gradle packages 20 | uses: actions/cache@v2 21 | with: 22 | path: | 23 | ~/.gradle/caches 24 | ~/.gradle/wrapper 25 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} 26 | restore-keys: | 27 | ${{ runner.os }}-gradle- 28 | - name: Build with Gradle 29 | run: | 30 | chmod +x ./gradlew 31 | ./gradlew buildPlugin 32 | - name: Cleanup Gradle Cache 33 | # Remove some files from the Gradle cache, so they aren't cached by GitHub Actions. 34 | # Restoring these files from a GitHub Actions cache might cause problems for future builds. 35 | run: | 36 | rm -f ~/.gradle/caches/modules-2/modules-2.lock 37 | rm -f ~/.gradle/caches/modules-2/gc.properties 38 | - name: Upload Artifacts 39 | uses: actions/upload-artifact@v2 40 | with: 41 | name: Artifacts 42 | path: build/distributions -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # JetBrains Copilot 2 | 3 | GitHub Copilot support for the IntelliJ Platform. 4 | 5 | # Deprecation Notice 6 | 7 | > GitHub has recently released an official IntelliJ plugin for copilot. 8 | > Please **uninstall** JetBrains Copilot and follow the guide [here](https://github.com/github/copilot-docs/blob/main/docs/gettingstartedjetbrains.md) 9 | > to install the official version of the plugin. 10 | > **Thank you** for the support on this small project of mine! 11 | 12 | *For archival purposes, this repository has been marked as read-only. 13 | As noted in the FAQ, this plugin will only be maintained and updated until 14 | GitHub releases their own version of the plugin, which is now public.* 15 | 16 | ## Installation 17 | 18 | Download the [latest release](https://github.com/KodingDev/JetBrainsCopilot/releases). 19 | Select the `Install Plugin from Disk` option in IntelliJ's plugin menu, then select the 20 | downloaded ZIP. Then **restart IntelliJ**. 21 | 22 | ![Plugins Menu](https://i.imgur.com/2nWt1PK.png) 23 | ## FAQ 24 | 25 | #### Is this officially supported by GitHub? 26 | 27 | **No**. JetBrains Copilot is a third-party plugin and has **no affiliation with GitHub**. 28 | As such, use it at your own risk, as we use some internal APIs from the Visual Studio Code plugin. 29 | 30 | #### How long will this be maintained? 31 | 32 | The plugin will be maintained until GitHub creates their own official plugin. 33 | ## Acknowledgements 34 | 35 | - [GitHub Copilot](https://copilot.github.com) 36 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/koding/copilot/config/ApplicationConfigurable.kt: -------------------------------------------------------------------------------- 1 | package dev.koding.copilot.config 2 | 3 | import com.intellij.openapi.options.Configurable 4 | import dev.koding.copilot.auth.handleLogin 5 | import java.text.NumberFormat 6 | import javax.swing.JButton 7 | import javax.swing.JFormattedTextField 8 | import javax.swing.JPanel 9 | import javax.swing.JTextField 10 | import javax.swing.text.DefaultFormatterFactory 11 | import javax.swing.text.NumberFormatter 12 | 13 | class ApplicationConfigurable : Configurable { 14 | 15 | private lateinit var panel: JPanel 16 | private lateinit var copilotToken: JTextField 17 | private lateinit var contextLines: JFormattedTextField 18 | private lateinit var loginButton: JButton 19 | 20 | override fun apply() { 21 | settings.token = copilotToken.text 22 | settings.contentLines = contextLines.text.toIntOrNull() ?: 10 23 | } 24 | 25 | override fun createComponent(): JPanel { 26 | contextLines.formatterFactory = DefaultFormatterFactory(NumberFormatter(NumberFormat.getIntegerInstance())) 27 | loginButton.addActionListener { handleLogin { copilotToken.text = it } } 28 | return panel 29 | } 30 | 31 | override fun reset() { 32 | copilotToken.text = settings.token ?: "" 33 | contextLines.text = settings.contentLines.toString() 34 | } 35 | 36 | override fun getDisplayName() = "GitHub Copilot" 37 | override fun isModified() = settings.token != copilotToken.text || 38 | settings.contentLines != (contextLines.text.toIntOrNull() ?: 10) 39 | } -------------------------------------------------------------------------------- /src/main/kotlin/dev/koding/copilot/auth/OAuthHandler.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("EXPERIMENTAL_API_USAGE") 2 | 3 | package dev.koding.copilot.auth 4 | 5 | import com.google.gson.annotations.SerializedName 6 | import com.intellij.ide.BrowserUtil 7 | import dev.koding.copilot.config.settings 8 | import dev.koding.copilot.httpClient 9 | import dev.koding.copilot.util.Notifications 10 | import io.ktor.client.request.* 11 | import io.ktor.http.* 12 | import kotlinx.coroutines.GlobalScope 13 | import kotlinx.coroutines.launch 14 | import javax.swing.JOptionPane 15 | 16 | const val authenticateUrl = "https://vscode-auth.github.com/authorize/" + 17 | "?callbackUri=vscode://vscode.github-authentication/did-authenticate" + 18 | "&scope=read:user" + 19 | "&responseType=code" + 20 | "&authServer=https://github.com" 21 | 22 | data class GitHubTokenResponse( 23 | @SerializedName("access_token") 24 | val accessToken: String?, 25 | @SerializedName("token_type") 26 | val tokenType: String?, 27 | val scope: String? 28 | ) 29 | 30 | data class CopilotTokenResponse( 31 | val token: String, 32 | @SerializedName("expires_at") 33 | val expiry: Int 34 | ) 35 | 36 | private suspend fun getAuthToken(url: String): CopilotTokenResponse { 37 | val code = Url(url).parameters["code"] ?: error("Code not present") 38 | 39 | val tokenResponse = httpClient.post("https://vscode-auth.github.com/token") { 40 | parameter("code", code) 41 | accept(ContentType.Application.Json) 42 | } 43 | 44 | return httpClient.get("https://api.github.com/copilot_internal/token") { 45 | header("Authorization", "token ${tokenResponse.accessToken ?: error("Invalid GitHub token")}") 46 | } 47 | } 48 | 49 | fun handleLogin(handler: (String) -> Unit = { Notifications.send("Login successful") }) { 50 | BrowserUtil.browse(authenticateUrl) 51 | val url = JOptionPane.showInputDialog("Enter the callback URL") 52 | 53 | // TODO: Change from global scope 54 | GlobalScope.launch { 55 | val token = getAuthToken(url).token 56 | settings.token = token 57 | handler(token) 58 | } 59 | } -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/pluginIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml 3 | 4 | 5 | Layer 1 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/koding/copilot/config/ApplicationConfigurable.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/koding/copilot/completion/CopilotCompletionContributor.kt: -------------------------------------------------------------------------------- 1 | package dev.koding.copilot.completion 2 | 3 | import com.intellij.codeInsight.completion.CompletionContributor 4 | import com.intellij.codeInsight.completion.CompletionParameters 5 | import com.intellij.codeInsight.completion.CompletionResultSet 6 | import com.intellij.codeInsight.completion.CompletionSorter 7 | import com.intellij.codeInsight.lookup.LookupElementBuilder 8 | import com.intellij.notification.NotificationType 9 | import com.intellij.openapi.progress.ProcessCanceledException 10 | import com.intellij.openapi.progress.ProgressManager 11 | import com.intellij.openapi.util.TextRange 12 | import dev.koding.copilot.auth.handleLogin 13 | import dev.koding.copilot.completion.api.CompletionRequest 14 | import dev.koding.copilot.completion.api.CompletionResponse 15 | import dev.koding.copilot.config.settings 16 | import dev.koding.copilot.copilotIcon 17 | import dev.koding.copilot.util.Notifications 18 | import io.ktor.client.features.* 19 | import kotlinx.coroutines.GlobalScope 20 | import kotlinx.coroutines.launch 21 | import kotlin.math.max 22 | 23 | 24 | class CopilotCompletionContributor : CompletionContributor() { 25 | 26 | override fun fillCompletionVariants(parameters: CompletionParameters, result: CompletionResultSet) { 27 | if (parameters.isAutoPopup) return 28 | 29 | if (settings.token == null || settings.token?.isBlank() == true) return Notifications.send( 30 | "You have not set a token for GitHub Copilot.", 31 | type = NotificationType.ERROR, 32 | once = true, 33 | Notifications.NotificationAction("Login") { handleLogin() }) 34 | 35 | val (prefix, suffix) = parameters.prefixSuffix 36 | val prompt = """ 37 | // Language: ${parameters.originalFile.language.displayName} 38 | // Path: ${parameters.originalFile.name} 39 | ${parameters.prompt} 40 | """.trimIndent() 41 | 42 | val matcher = result.prefixMatcher 43 | val set = result 44 | .withPrefixMatcher(CopilotPrefixMatcher(matcher.cloneWithPrefix(matcher.prefix))) 45 | .withRelevanceSorter(CompletionSorter.defaultSorter(parameters, matcher).weigh(CopilotWeigher())) 46 | 47 | var response: CompletionResponse? = null 48 | var errored = false 49 | 50 | val job = GlobalScope.launch { 51 | try { 52 | response = CompletionRequest(prompt).send(settings.token!!) 53 | } catch (e: ClientRequestException) { 54 | e.printStackTrace() 55 | errored = true 56 | return@launch Notifications.send( 57 | "Failed to fetch response. Is your copilot token valid?", 58 | type = NotificationType.ERROR, 59 | once = true, 60 | Notifications.NotificationAction("Login") { handleLogin() }) 61 | } catch (e: Exception) { 62 | e.printStackTrace() 63 | } 64 | } 65 | 66 | while (response == null) { 67 | if (errored) return 68 | try { 69 | ProgressManager.getInstance().progressIndicator.checkCanceled() 70 | Thread.sleep(10) 71 | } catch (e: ProcessCanceledException) { 72 | job.cancel() 73 | return 74 | } 75 | } 76 | 77 | val choices = response!!.choices.filter { it.text.isNotBlank() } 78 | if (choices.isEmpty()) return 79 | 80 | set.restartCompletionOnAnyPrefixChange() 81 | set.addAllElements(choices.map { choice -> 82 | val completion = choice.text.removePrefix(prefix.trim()).removeSuffix(suffix.trim()) 83 | val insert = "$prefix${completion.trim()}\n" 84 | 85 | LookupElementBuilder.create(choice, "") 86 | .withInsertHandler { context, _ -> 87 | val caret = context.editor.caretModel 88 | val startOffset = caret.visualLineStart 89 | val endOffset = caret.visualLineEnd 90 | 91 | context.document.deleteString(startOffset, endOffset) 92 | context.document.insertString(startOffset, insert) 93 | caret.moveToOffset(startOffset + insert.length - 1) 94 | } 95 | .withPresentableText(prefix.split(".").last().trim()) 96 | .withTailText(completion, true) 97 | .withCaseSensitivity(false) 98 | .withTypeText("GitHub Copilot") 99 | .withIcon(copilotIcon) 100 | .bold() 101 | }) 102 | } 103 | 104 | private val CompletionParameters.prompt: String 105 | get() { 106 | val document = editor.document 107 | val lineNumber = document.getLineNumber(offset) 108 | val startOffset = document.getLineStartOffset(max(0, lineNumber - settings.contentLines)) 109 | return document.getText(TextRange(startOffset, offset)) 110 | } 111 | 112 | private val CompletionParameters.prefixSuffix: Pair 113 | get() { 114 | val document = editor.document 115 | val lineNumber = document.getLineNumber(offset) 116 | 117 | val lineStart = document.getLineStartOffset(lineNumber) 118 | val lineEnd = document.getLineEndOffset(lineNumber) 119 | 120 | val start = document.getText(TextRange.create(lineStart, offset)) 121 | val end = document.getText(TextRange.create(offset, lineEnd)) 122 | return start to end 123 | } 124 | 125 | } -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MSYS* | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | --------------------------------------------------------------------------------