Skip to content
This repository was archived by the owner on Oct 24, 2021. It is now read-only.

Commit 3f556f2

Browse files
committed
Refactored & fixed a few issues with completions
1 parent fbb1c49 commit 3f556f2

File tree

7 files changed

+143
-139
lines changed

7 files changed

+143
-139
lines changed

src/main/kotlin/dev/koding/copilot/CopilotCompletionContributor.kt

Lines changed: 0 additions & 125 deletions
This file was deleted.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package dev.koding.copilot.completion
2+
3+
import com.intellij.codeInsight.completion.*
4+
import com.intellij.codeInsight.lookup.LookupElementBuilder
5+
import com.intellij.openapi.application.ex.ApplicationUtil
6+
import com.intellij.openapi.progress.ProgressManager
7+
import com.intellij.openapi.util.TextRange
8+
import dev.koding.copilot.completion.api.CompletionRequest
9+
import dev.koding.copilot.copilotIcon
10+
import kotlinx.coroutines.runBlocking
11+
import kotlin.math.max
12+
13+
14+
class CopilotCompletionContributor : CompletionContributor() {
15+
16+
override fun fillCompletionVariants(parameters: CompletionParameters, result: CompletionResultSet) {
17+
if (parameters.isAutoPopup) return
18+
19+
val prompt = """
20+
// Language: ${parameters.originalFile.language.displayName}
21+
// Path: ${parameters.originalFile.name}
22+
${getPrompt(parameters)}
23+
""".trimIndent()
24+
25+
val (prefix, suffix) = parameters.prefixSuffix
26+
val response = ApplicationUtil.runWithCheckCanceled({
27+
return@runWithCheckCanceled runBlocking { CompletionRequest(prompt).send(System.getenv("GITHUB_COPILOT_TOKEN")) }
28+
}, ProgressManager.getInstance().progressIndicator) ?: return
29+
30+
val choices = response.choices.filter { it.text.isNotBlank() }
31+
if (choices.isEmpty()) return
32+
33+
val originalMatcher = result.prefixMatcher
34+
val set =
35+
result.withPrefixMatcher(CopilotPrefixMatcher(originalMatcher.cloneWithPrefix(originalMatcher.prefix)))
36+
.withRelevanceSorter(
37+
CompletionSorter.defaultSorter(parameters, originalMatcher)
38+
.weigh(CopilotWeigher())
39+
)
40+
41+
set.restartCompletionOnAnyPrefixChange()
42+
set.addAllElements(choices.map { choice ->
43+
val completion = choice.text.removePrefix(prefix).removeSuffix(suffix)
44+
.let {
45+
val split = prefix.split(".")
46+
if (split.size >= 2) "${split.last()}$it" else it
47+
}
48+
49+
PrioritizedLookupElement.withPriority(
50+
LookupElementBuilder.create(choice, completion)
51+
.withPresentableText(prefix)
52+
.withTailText(completion, true)
53+
.withTypeText("GitHub Copilot")
54+
.withIcon(copilotIcon)
55+
.bold(), Double.MAX_VALUE
56+
)
57+
})
58+
}
59+
60+
private fun getPrompt(parameters: CompletionParameters): String {
61+
// Using the parameters, get the last 10 lines of the current editor document and return their text
62+
val lineNumber = parameters.editor.document.getLineNumber(parameters.offset)
63+
val startOffset = parameters.editor.document.getLineStartOffset(max(0, lineNumber - 10))
64+
return parameters.editor.document.getText(TextRange(startOffset, parameters.offset))
65+
}
66+
67+
private val CompletionParameters.prefixSuffix: Pair<String, String>
68+
get() {
69+
val document = editor.document
70+
val lineNumber = document.getLineNumber(offset)
71+
72+
val lineStart = document.getLineStartOffset(lineNumber)
73+
val lineEnd = document.getLineEndOffset(lineNumber)
74+
75+
val start = document.getText(TextRange.create(lineStart, offset))
76+
val end = document.getText(TextRange.create(offset, lineEnd)).trim()
77+
return start to end
78+
}
79+
80+
}

src/main/kotlin/dev/koding/copilot/CopilotPrefixMatcher.kt renamed to src/main/kotlin/dev/koding/copilot/completion/CopilotPrefixMatcher.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1-
package dev.koding.copilot
1+
package dev.koding.copilot.completion
22

33
import com.intellij.codeInsight.completion.PrefixMatcher
44
import com.intellij.codeInsight.lookup.LookupElement
55
import com.intellij.codeInsight.lookup.LookupElementDecorator
6+
import dev.koding.copilot.completion.api.CompletionChoice
67

78
class CopilotPrefixMatcher(private val inner: PrefixMatcher) : PrefixMatcher(inner.prefix) {
89
override fun prefixMatches(element: LookupElement): Boolean {
9-
if (element.`object` is CopilotCompletionContributor.ResponseChoice) return true
10+
if (element.`object` is CompletionChoice) return true
1011
else if (element is LookupElementDecorator<*>) return prefixMatches(element.delegate)
1112
return super.prefixMatches(element)
1213
}
1314

1415
override fun isStartMatch(element: LookupElement?): Boolean {
15-
if (element?.`object` is CopilotCompletionContributor.ResponseChoice) return true
16+
if (element?.`object` is CompletionChoice) return true
1617
return super.isStartMatch(element)
1718
}
1819

Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
package dev.koding.copilot
1+
package dev.koding.copilot.completion
22

33
import com.intellij.codeInsight.lookup.LookupElement
44
import com.intellij.codeInsight.lookup.LookupElementWeigher
5+
import dev.koding.copilot.completion.api.CompletionChoice
56

67
class CopilotWeigher : LookupElementWeigher("CopilotLookupElementWeigher", false, true) {
78

89
override fun weigh(element: LookupElement) =
9-
if (element.`object` is CopilotCompletionContributor.ResponseChoice) Int.MIN_VALUE else Int.MAX_VALUE
10+
if (element.`object` is CompletionChoice) Int.MIN_VALUE else Int.MAX_VALUE
1011

1112
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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<CompletionChoice>
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 = 50,
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<String> = listOf("\n")
27+
) {
28+
suspend fun send(token: String): CompletionResponse? =
29+
httpClient.post<CompletionResponse>("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+
35+
body = this@CompletionRequest
36+
}
37+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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/resources/META-INF/plugin.xml

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,19 @@
44
<vendor email="me@koding.dev" url="https://koding.dev">Koding Dev</vendor>
55

66
<description><![CDATA[
7-
So awesome. gosh so epic. me chungus. me big chungus.
7+
Adds GitHub Copilot integration into the IntelliJ platform.
8+
This <b>IS NOT</b> an official product of GitHub and is meant for specialized use only.
89
]]></description>
910

1011
<!-- please see https://plugins.jetbrains.com/docs/intellij/plugin-compatibility.html
1112
on how to target different products -->
12-
<depends>com.intellij.modules.platform</depends>
13+
<depends>com.intellij.modules.lang</depends>
1314

1415
<idea-version since-build="201.4515.24"/>
1516

1617
<extensions defaultExtensionNs="com.intellij">
17-
<completion.contributor language="any" implementationClass="dev.koding.copilot.CopilotCompletionContributor" order="first"/>
18-
<!-- Add your extensions here -->
18+
<completion.contributor language="any"
19+
implementationClass="dev.koding.copilot.completion.CopilotCompletionContributor"
20+
order="first"/>
1921
</extensions>
20-
21-
<actions>
22-
23-
<!-- Add your actions here -->
24-
</actions>
2522
</idea-plugin>

0 commit comments

Comments
 (0)